diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroup.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroup.kt
index 36d79169a..085d33712 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroup.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroup.kt
@@ -19,8 +19,21 @@ interface VimVisualMotionGroup {
    * Enters Visual mode, ensuring that the caret's selection start offset is correctly set
    *
    * Use this to programmatically enter Visual mode. Note that it does not modify the editor's selection.
+   *
+   * This overload needs to remain for compatibility with external IdeaVim extensions
    */
-  fun enterVisualMode(editor: VimEditor, selectionType: SelectionType): Boolean
+  fun enterVisualMode(editor: VimEditor, selectionType: SelectionType): Boolean {
+    return enterVisualMode(editor, selectionType, Mode.NORMAL())
+  }
+
+  /**
+   * Enters Visual mode, ensuring that the caret's selection start offset is correctly set
+   *
+   * Use this to programmatically enter Visual mode. Note that it does not modify the editor's selection. You can
+   * specify the mode to return to when Visual command exits. Typically, this is [Mode.NORMAL], but can be [Mode.INSERT]
+   * or [Mode.REPLACE] for "Insert Visual" or [Mode.SELECT] when processing a single Visual command in Select mode.
+   */
+  fun enterVisualMode(editor: VimEditor, selectionType: SelectionType, returnTo: Mode): Boolean
 
   /**
    * Enter Select mode with the given selection type
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroupBase.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroupBase.kt
index 572e92b2a..1056ba04f 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroupBase.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimVisualMotionGroupBase.kt
@@ -31,8 +31,8 @@ abstract class VimVisualMotionGroupBase : VimVisualMotionGroup {
    *
    * Use this to programmatically enter Visual mode. Note that it does not modify the editor's selection.
    */
-  override fun enterVisualMode(editor: VimEditor, selectionType: SelectionType): Boolean {
-    editor.mode = Mode.VISUAL(selectionType)
+  override fun enterVisualMode(editor: VimEditor, selectionType: SelectionType, returnTo: Mode): Boolean {
+    editor.mode = Mode.VISUAL(selectionType, returnTo)
 
     // vimLeadSelectionOffset requires read action
     injector.application.runReadAction {
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/handler/SpecialKeyHandlers.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/handler/SpecialKeyHandlers.kt
index 79a83f9b1..6a4f30170 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/handler/SpecialKeyHandlers.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/handler/SpecialKeyHandlers.kt
@@ -61,7 +61,7 @@ abstract class ShiftedSpecialKeyHandler : VimActionHandler.ConditionalMulticaret
       if (injector.globalOptions().selectmode.contains(OptionConstants.selectmode_key)) {
         injector.visualMotionGroup.enterSelectMode(editor, SelectionType.CHARACTER_WISE)
       } else {
-        injector.visualMotionGroup.toggleVisual(editor, 1, 0, SelectionType.CHARACTER_WISE)
+        injector.visualMotionGroup.enterVisualMode(editor, SelectionType.CHARACTER_WISE)
       }
     }
     return true
@@ -97,10 +97,10 @@ abstract class ShiftedArrowKeyHandler(private val runBothCommandsAsMulticaret: B
           injector.visualMotionGroup.enterSelectMode(editor, SelectionType.CHARACTER_WISE)
         } else {
           if (editor.isInsertionAllowed) {
-            // Enter Insert/Replace Visual mode
-            injector.visualMotionGroup.toggleVisual(editor, 1, 0, SelectionType.CHARACTER_WISE, editor.mode)
+            // Enter Insert/Replace Visual mode, passing in the current Insert/Replace mode as pending
+            injector.visualMotionGroup.enterVisualMode(editor, SelectionType.CHARACTER_WISE, editor.mode)
           } else {
-            injector.visualMotionGroup.toggleVisual(editor, 1, 0, SelectionType.CHARACTER_WISE)
+            injector.visualMotionGroup.enterVisualMode(editor, SelectionType.CHARACTER_WISE)
           }
         }
       }