diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 5cbab34f..ceb01ef3 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -237,6 +237,7 @@ impl Command {
         goto_window_bottom, "Goto window bottom",
         goto_last_accessed_file, "Goto last accessed file",
         goto_line, "Goto line",
+        goto_last_line, "Goto last line",
         goto_first_diag, "Goto first diagnostic",
         goto_last_diag, "Goto last diagnostic",
         goto_next_diag, "Goto next diagnostic",
@@ -2426,12 +2427,32 @@ fn goto_line(cx: &mut Context) {
         push_jump(cx.editor);
 
         let (view, doc) = current!(cx.editor);
-        let line_idx = std::cmp::min(count.get() - 1, doc.text().len_lines().saturating_sub(2));
+        let max_line = if doc.text().line(doc.text().len_lines() - 1).len_chars() == 0 {
+            // If the last line is blank, don't jump to it.
+            doc.text().len_lines().saturating_sub(2)
+        } else {
+            doc.text().len_lines() - 1
+        };
+        let line_idx = std::cmp::min(count.get() - 1, max_line);
         let pos = doc.text().line_to_char(line_idx);
         doc.set_selection(view.id, Selection::point(pos));
     }
 }
 
+fn goto_last_line(cx: &mut Context) {
+    push_jump(cx.editor);
+
+    let (view, doc) = current!(cx.editor);
+    let line_idx = if doc.text().line(doc.text().len_lines() - 1).len_chars() == 0 {
+        // If the last line is blank, don't jump to it.
+        doc.text().len_lines().saturating_sub(2)
+    } else {
+        doc.text().len_lines() - 1
+    };
+    let pos = doc.text().line_to_char(line_idx);
+    doc.set_selection(view.id, Selection::point(pos));
+}
+
 fn goto_last_accessed_file(cx: &mut Context) {
     let alternate_file = view!(cx.editor).last_accessed_doc;
     if let Some(alt) = alternate_file {
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index 5fe730a1..cba3b3d0 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -359,7 +359,7 @@ impl Default for Keymaps {
             "G" => goto_line,
             "g" => { "Goto"
                 "g" => goto_file_start,
-                "e" => goto_file_end,
+                "e" => goto_last_line,
                 "h" => goto_line_start,
                 "l" => goto_line_end,
                 "s" => goto_first_nonwhitespace,
@@ -617,7 +617,7 @@ fn merge_partial_keys() {
     // Assumes that `ge` is in default keymap
     assert_eq!(
         keymap.root().search(&[key!('g'), key!('e')]).unwrap(),
-        &KeyTrie::Leaf(Command::goto_file_end),
+        &KeyTrie::Leaf(Command::goto_last_line),
         "Old leaves in subnode should be present in merged node"
     );