diff --git a/lib/base.php b/lib/base.php
index 7f666daceb25d4ee368789f6eb438a59f342542e..115a0968af2ccd7e84df5790c1577110e62eef71 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -641,7 +641,7 @@ class OC {
 
 		/** @var \OC\AppFramework\Bootstrap\Coordinator $bootstrapCoordinator */
 		$bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
-		$bootstrapCoordinator->runRegistration();
+		$bootstrapCoordinator->runInitialRegistration();
 
 		\OC::$server->getEventLogger()->start('init_session', 'Initialize session');
 		OC_App::loadApps(['session']);
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php
index c8155c3b5bae15c53b682892055a17209d69c46c..06a17e5242b576309f8c4605e3e32851e4f0fb9f 100644
--- a/lib/private/AppFramework/Bootstrap/Coordinator.php
+++ b/lib/private/AppFramework/Bootstrap/Coordinator.php
@@ -38,7 +38,6 @@ use OCP\Dashboard\IManager;
 use OCP\EventDispatcher\IEventDispatcher;
 use OCP\ILogger;
 use OCP\IServerContainer;
-use RuntimeException;
 use Throwable;
 use function class_exists;
 use function class_implements;
@@ -79,14 +78,23 @@ class Coordinator {
 		$this->logger = $logger;
 	}
 
-	public function runRegistration(): void {
-		if ($this->registrationContext !== null) {
-			throw new RuntimeException('Registration has already been run');
-		}
+	public function runInitialRegistration(): void {
+		$this->registerApps(OC_App::getEnabledApps());
+	}
 
-		$this->registrationContext = new RegistrationContext($this->logger);
+	public function runLazyRegistration(string $appId): void {
+		$this->registerApps([$appId]);
+	}
+
+	/**
+	 * @param string[] $appIds
+	 */
+	private function registerApps(array $appIds): void {
+		if ($this->registrationContext === null) {
+			$this->registrationContext = new RegistrationContext($this->logger);
+		}
 		$apps = [];
-		foreach (OC_App::getEnabledApps() as $appId) {
+		foreach ($appIds as $appId) {
 			/*
 			 * First, we have to enable the app's autoloader
 			 *
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index 023590596e3506916ff4f3f659fde06161079240..68e2701de271402cad65f883a4490ee499d37907 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -264,7 +264,7 @@ class RegistrationContext {
 	 * @param App[] $apps
 	 */
 	public function delegateCapabilityRegistrations(array $apps): void {
-		foreach ($this->capabilities as $registration) {
+		while (($registration = array_pop($this->capabilities)) !== null) {
 			try {
 				$apps[$registration['appId']]
 					->getContainer()
@@ -283,7 +283,7 @@ class RegistrationContext {
 	 * @param App[] $apps
 	 */
 	public function delegateCrashReporterRegistrations(array $apps, Registry $registry): void {
-		foreach ($this->crashReporters as $registration) {
+		while (($registration = array_pop($this->crashReporters)) !== null) {
 			try {
 				$registry->registerLazy($registration['class']);
 			} catch (Throwable $e) {
@@ -300,7 +300,7 @@ class RegistrationContext {
 	 * @param App[] $apps
 	 */
 	public function delegateDashboardPanelRegistrations(array $apps, IManager $dashboardManager): void {
-		foreach ($this->dashboardPanels as $panel) {
+		while (($panel = array_pop($this->dashboardPanels)) !== null) {
 			try {
 				$dashboardManager->lazyRegisterWidget($panel['class']);
 			} catch (Throwable $e) {
@@ -314,7 +314,7 @@ class RegistrationContext {
 	}
 
 	public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void {
-		foreach ($this->eventListeners as $registration) {
+		while (($registration = array_pop($this->eventListeners)) !== null) {
 			try {
 				if (isset($registration['priority'])) {
 					$eventDispatcher->addServiceListener(
@@ -342,7 +342,7 @@ class RegistrationContext {
 	 * @param App[] $apps
 	 */
 	public function delegateContainerRegistrations(array $apps): void {
-		foreach ($this->services as $registration) {
+		while (($registration = array_pop($this->services)) !== null) {
 			try {
 				/**
 				 * Register the service and convert the callable into a \Closure if necessary
@@ -402,7 +402,7 @@ class RegistrationContext {
 	 * @param App[] $apps
 	 */
 	public function delegateMiddlewareRegistrations(array $apps): void {
-		foreach ($this->middlewares as $middleware) {
+		while (($middleware = array_pop($this->middlewares)) !== null) {
 			try {
 				$apps[$middleware['appId']]
 					->getContainer()
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 9388711697a85b60e13c61f2ad77b6315bb8d170..a2c4f9beff8447ed08e0b6a99a3cc4eeb6e11158 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -42,6 +42,7 @@ namespace OC;
 use Doctrine\DBAL\Exception\TableExistsException;
 use OC\App\AppStore\Bundles\Bundle;
 use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\AppFramework\Bootstrap\Coordinator;
 use OC\Archive\TAR;
 use OC_App;
 use OC_DB;
@@ -138,6 +139,9 @@ class Installer {
 
 		// check for required dependencies
 		\OC_App::checkAppDependencies($this->config, $l, $info, $ignoreMax);
+		/** @var Coordinator $coordinator */
+		$coordinator = \OC::$server->get(Coordinator::class);
+		$coordinator->runLazyRegistration($appId);
 		\OC_App::registerAutoloading($appId, $basedir);
 
 		$previousVersion = $this->config->getAppValue($info['id'], 'installed_version', false);