diff --git a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
index e8da5211583e42fd4a1852ae4e984449722fa10e..ec6f3867f34a205b3a1fa4c2cfd2759a93d8f5bf 100644
--- a/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
+++ b/typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
@@ -23,7 +23,9 @@ use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
+use TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
+use TYPO3\CMS\Extbase\Mvc\View\ViewResolverInterface;
 use TYPO3\CMS\Extbase\Mvc\Web\ReferringRequest;
 use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
 use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
@@ -50,6 +52,11 @@ class ActionController implements ControllerInterface
      */
     protected $hashService;
 
+    /**
+     * @var ViewResolverInterface
+     */
+    private $viewResolver;
+
     /**
      * The current view, as resolved by resolveView()
      *
@@ -103,6 +110,15 @@ class ActionController implements ControllerInterface
      */
     protected $response;
 
+    /**
+     * @param ViewResolverInterface $viewResolver
+     * @internal
+     */
+    public function injectViewResolver(ViewResolverInterface $viewResolver)
+    {
+        $this->viewResolver = $viewResolver;
+    }
+
     /**
      * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
      */
@@ -371,10 +387,22 @@ class ActionController implements ControllerInterface
      */
     protected function resolveView()
     {
-        $view = null;
-        if ($this->defaultViewObjectName != '') {
-            /** @var ViewInterface $view */
-            $view = $this->objectManager->get($this->defaultViewObjectName);
+        if ($this->viewResolver instanceof GenericViewResolver) {
+            /*
+             * This setter is not part of the ViewResolverInterface as it's only necessary to set
+             * the default view class from this point when using the generic view resolver which
+             * must respect the possibly overridden property defaultViewObjectName.
+             */
+            $this->viewResolver->setDefaultViewClass($this->defaultViewObjectName);
+        }
+
+        $view = $this->viewResolver->resolve(
+            $this->request->getControllerObjectName(),
+            $this->request->getControllerActionName(),
+            $this->request->getFormat()
+        );
+
+        if ($view instanceof ViewInterface) {
             $this->setViewConfiguration($view);
             if ($view->canRender($this->controllerContext) === false) {
                 $view = null;
diff --git a/typo3/sysext/extbase/Classes/Mvc/View/GenericViewResolver.php b/typo3/sysext/extbase/Classes/Mvc/View/GenericViewResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..766c85c4393bddf4f95b8cbd7049016d69a83de3
--- /dev/null
+++ b/typo3/sysext/extbase/Classes/Mvc/View/GenericViewResolver.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace TYPO3\CMS\Extbase\Mvc\View;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+
+/**
+ * @internal only to be used within Extbase, not part of TYPO3 Core API.
+ */
+class GenericViewResolver implements ViewResolverInterface
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var string
+     */
+    private $defaultViewClass;
+
+    public function __construct(ObjectManager $objectManager)
+    {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * @param string $defaultViewClass
+     * @internal
+     */
+    public function setDefaultViewClass(string $defaultViewClass): void
+    {
+        $this->defaultViewClass = $defaultViewClass;
+    }
+
+    public function resolve(string $controllerObjectName, string $actionName, string $format): ViewInterface
+    {
+        return $this->objectManager->get($this->defaultViewClass);
+    }
+}
diff --git a/typo3/sysext/extbase/Classes/Mvc/View/ViewResolverInterface.php b/typo3/sysext/extbase/Classes/Mvc/View/ViewResolverInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..27ee2f9c334942b8e5769e77aa776380bbb4719b
--- /dev/null
+++ b/typo3/sysext/extbase/Classes/Mvc/View/ViewResolverInterface.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+
+namespace TYPO3\CMS\Extbase\Mvc\View;
+
+/**
+ * @internal only to be used within Extbase, not part of TYPO3 Core API.
+ *
+ * It's safe to use this interface in TYPO3 10 LTS as it will not be changed or removed in that
+ * version but this interface is likely to be removed and/or changed in version 11.
+ */
+interface ViewResolverInterface
+{
+    public function resolve(string $controllerObjectName, string $actionName, string $format): ViewInterface;
+}
diff --git a/typo3/sysext/extbase/Configuration/Services.yaml b/typo3/sysext/extbase/Configuration/Services.yaml
index e393761fbb7b76e199c62248e54bb51ecee8f4e8..d0c5dfda66bc86bb9ed68ad9261fc82114d16a82 100644
--- a/typo3/sysext/extbase/Configuration/Services.yaml
+++ b/typo3/sysext/extbase/Configuration/Services.yaml
@@ -83,3 +83,6 @@ services:
         identifier: 'legacy-slot'
         method: 'emitAfterPersistObjectSignal'
         event: TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent
+
+  TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver: ~
+  TYPO3\CMS\Extbase\Mvc\View\ViewResolverInterface: '@TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver'
diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php
index e8fabffe25055cc8173af8a6831fafafca22dc7a..e68796e94346dbb443609336f7a694e9254c982b 100644
--- a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php
+++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ActionControllerTest.php
@@ -18,6 +18,7 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\View\JsonView;
 use TYPO3\CMS\Extbase\Mvc\Web\Request;
 use TYPO3\CMS\Extbase\Mvc\Web\Response;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -118,4 +119,29 @@ class ActionControllerTest extends \TYPO3\TestingFramework\Core\Functional\Funct
         $validators->rewind();
         self::assertInstanceOf(NotEmptyValidator::class, $validators->current());
     }
+
+    /**
+     * @test
+     */
+    public function resolveViewRespectsDefaultViewObjectName()
+    {
+        // Test setup
+        $reflectionClass = new \ReflectionClass($this->controller);
+        $reflectionMethod = $reflectionClass->getProperty('defaultViewObjectName');
+        $reflectionMethod->setAccessible(true);
+        $reflectionMethod->setValue($this->controller, JsonView::class);
+
+        $this->request->setControllerActionName('qux');
+
+        // Test run
+        $this->controller->processRequest($this->request, $this->response);
+
+        // Assertions
+        $reflectionMethod = $reflectionClass->getProperty('view');
+        $reflectionMethod->setAccessible(true);
+        $reflectionMethod->getValue($this->controller);
+
+        $view = $reflectionMethod->getValue($this->controller);
+        self::assertInstanceOf(JsonView::class, $view);
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php
index 32f9ec608e865efd928e8b347a9bad99c6e46c53..6f2b22aead7c6aab569ea310ed9350ad63422a33 100644
--- a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php
+++ b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/Fixture/Controller/TestController.php
@@ -71,4 +71,9 @@ class TestController extends ActionController
         // return string so we don't need to mock a view
         return '';
     }
+
+    public function quxAction()
+    {
+        return '';
+    }
 }