diff --git a/core/core.services.yml b/core/core.services.yml
index bf21661..44fba5e 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -339,6 +339,9 @@ services:
   logger.channel.form:
     parent: logger.channel_base
     arguments: ['form']
+  logger.channel.modules:
+    parent: logger.channel_base
+    arguments: ['modules']
   logger.log_message_parser:
     class: Drupal\Core\Logger\LogMessageParser
 
@@ -408,6 +411,7 @@ services:
     arguments: ['@app.root', '%container.modules%', '@cache.bootstrap']
   module_installer:
     class: Drupal\Core\Extension\ModuleInstaller
+    arguments: ['@app.root', '@module_handler', '@kernel', '@config.factory', '@config.installer', '@plugin.cache_clearer', '@router.builder', '@entity.manager', '@stream_wrapper_manager', '@theme_handler', '@logger.channel.modules', '@config.manager', '@keyvalue']
     tags:
       - { name: service_collector, tag: 'module_install.uninstall_validator', call: addUninstallValidator }
     arguments: ['@app.root', '@module_handler', '@kernel']
diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateDependenciesTrait.php b/core/lib/Drupal/Core/DependencyInjection/UpdateDependenciesTrait.php
new file mode 100644
index 0000000..c7e706f
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/UpdateDependenciesTrait.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\UpdateDependenciesTrait.
+ */
+
+namespace Drupal\Core\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a trait which automatically updates dependencies from the container.
+ *
+ * Classes which trigger a container rebuild should point to the instances of
+ * the services with the new container. Calling the ::updateDependencies()
+ * method takes care of that.
+ *
+ * If the service depends on container parameters and if they can possibly
+ * change then the service will need to handle this itself.
+ */
+trait UpdateDependenciesTrait {
+
+  /**
+   * Updates an object's external dependencies from the container.
+   *
+   * This method depends on \Drupal\Core\DependencyInjection\Container::get()
+   * adding the _serviceId property to all services.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The container.
+   *
+   * @see \Drupal\Core\DependencyInjection\Container
+   */
+  protected function updateDependencies(ContainerInterface $container) {
+    $vars = get_object_vars($this);
+    foreach ($vars as $key => $value) {
+      if (is_object($value) && isset($value->_serviceId)) {
+        $this->$key = $container->get($value->_serviceId);
+      }
+      // Special case the container, which might not have a service ID.
+      elseif ($value instanceof ContainerInterface) {
+        $this->$key = $container;
+      }
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index 56902a7..821bda8 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -10,10 +10,18 @@
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Config\PreExistingConfigException;
-use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ConfigInstallerInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
+use Drupal\Core\DependencyInjection\UpdateDependenciesTrait;
 use Drupal\Core\DrupalKernelInterface;
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
+use Drupal\Core\Plugin\CachedDiscoveryClearerInterface;
+use Drupal\Core\Routing\RouteBuilderInterface;
+use Drupal\Core\StreamWrapper\StreamWrapperManager;
+use Psr\Log\LoggerInterface;
 
 /**
  * Default implementation of the module installer.
@@ -23,6 +31,8 @@
  */
 class ModuleInstaller implements ModuleInstallerInterface {
 
+  use UpdateDependenciesTrait;
+
   /**
    * The module handler.
    *
@@ -52,6 +62,76 @@ class ModuleInstaller implements ModuleInstallerInterface {
   protected $uninstallValidators;
 
   /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The config installer.
+   *
+   * @var \Drupal\Core\Config\ConfigInstallerInterface
+   */
+  protected $configInstaller;
+
+  /**
+   * The plugin cache clearer.
+   *
+   * @var \Drupal\Core\Plugin\CachedDiscoveryClearerInterface
+   */
+  protected $pluginCacheClearer;
+
+  /**
+   * The route builder.
+   *
+   * @var \Drupal\Core\Routing\RouteBuilderInterface
+   */
+  protected $routeBuilder;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * The stream wrapper manager.
+   *
+   * @var \Drupal\Core\StreamWrapper\StreamWrapperManager
+   */
+  protected $streamWrapperManager;
+
+  /**
+   * The theme handler.
+   *
+   * @var \Drupal\Core\Extension\ThemeHandlerInterface
+   */
+  protected $themeHandler;
+
+  /**
+   * The logger.
+   *
+   * @var \Psr\Log\LoggerInterface
+   */
+  protected $logger;
+
+  /**
+   * The config manager.
+   *
+   * @var \Drupal\Core\Config\ConfigManagerInterface
+   */
+  protected $configManager;
+
+  /**
+   * The key value factory.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface
+   */
+  protected $keyValueFactory;
+
+  /**
    * Constructs a new ModuleInstaller instance.
    *
    * @param string $root
@@ -60,14 +140,44 @@ class ModuleInstaller implements ModuleInstallerInterface {
    *   The module handler.
    * @param \Drupal\Core\DrupalKernelInterface $kernel
    *   The drupal kernel.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   * @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer
+   *   The config installer.
+   * @param \Drupal\Core\Plugin\CachedDiscoveryClearerInterface $plugin_cache_clearer
+   *   The plugin cache clearer.
+   * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
+   *   The route builder.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\StreamWrapper\StreamWrapperManager $stream_wrapper_manager
+   *   The stream wrapper manager.
+   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
+   *   The theme handler.
+   * @param \Psr\Log\LoggerInterface $logger
+   *   The logger.
+   * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
+   *   The config manager.
+   * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
+   *   The key value factory.
    *
    * @see \Drupal\Core\DrupalKernel
    * @see \Drupal\Core\CoreServiceProvider
    */
-  public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel) {
+  public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, ConfigFactoryInterface $config_factory, ConfigInstallerInterface $config_installer, CachedDiscoveryClearerInterface $plugin_cache_clearer, RouteBuilderInterface $route_builder, EntityManagerInterface $entity_manager, StreamWrapperManager $stream_wrapper_manager, ThemeHandlerInterface $theme_handler, LoggerInterface $logger, ConfigManagerInterface $config_manager, KeyValueFactoryInterface $key_value_factory) {
     $this->root = $root;
     $this->moduleHandler = $module_handler;
     $this->kernel = $kernel;
+    $this->configFactory = $config_factory;
+    $this->configInstaller = $config_installer;
+    $this->pluginCacheClearer = $plugin_cache_clearer;
+    $this->routeBuilder = $route_builder;
+    $this->entityManager = $entity_manager;
+    $this->streamWrapperManager = $stream_wrapper_manager;
+    $this->themeHandler = $theme_handler;
+    $this->logger = $logger;
+    $this->configManager = $config_manager;
+    $this->keyValueFactory = $key_value_factory;
   }
 
   /**
@@ -81,7 +191,7 @@ public function addUninstallValidator(ModuleUninstallValidatorInterface $uninsta
    * {@inheritdoc}
    */
   public function install(array $module_list, $enable_dependencies = TRUE) {
-    $extension_config = \Drupal::configFactory()->getEditable('core.extension');
+    $extension_config = $this->configFactory->getEditable('core.extension');
     if ($enable_dependencies) {
       // Get all module data so we can find dependencies and sort.
       $module_data = system_rebuild_module_data();
@@ -133,11 +243,9 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
     // Required for module installation checks.
     include_once $this->root . '/core/includes/install.inc';
 
-    /** @var \Drupal\Core\Config\ConfigInstaller $config_installer */
-    $config_installer = \Drupal::service('config.installer');
-    $sync_status = $config_installer->isSyncing();
+    $sync_status = $this->configInstaller->isSyncing();
     if ($sync_status) {
-      $source_storage = $config_installer->getSourceStorage();
+      $source_storage = $this->configInstaller->getSourceStorage();
     }
     $modules_installed = array();
     foreach ($module_list as $module) {
@@ -153,7 +261,7 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
 
         // Check the validity of the default configuration. This will throw
         // exceptions if the configuration is not valid.
-        $config_installer->checkConfigurationToInstall('module', $module);
+        $this->configInstaller->checkConfigurationToInstall('module', $module);
 
         // Save this data without checking schema. This is a performance
         // improvement for module installation.
@@ -212,7 +320,7 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
         drupal_install_schema($module);
 
         // Clear plugin manager caches.
-        \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
+        $this->pluginCacheClearer->clearCachedDefinitions();
 
         // Set the schema version to the number of the last update provided by
         // the module, or the minimum core schema version.
@@ -226,21 +334,19 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
         // For example, a SQL-based storage handler can use this as an
         // opportunity to create the necessary database tables.
         // @todo Clean this up in https://www.drupal.org/node/2350111.
-        $entity_manager = \Drupal::entityManager();
-        foreach ($entity_manager->getDefinitions() as $entity_type) {
+        foreach ($this->entityManager->getDefinitions() as $entity_type) {
           if ($entity_type->getProvider() == $module) {
-            $entity_manager->onEntityTypeCreate($entity_type);
+            $this->entityManager->onEntityTypeCreate($entity_type);
           }
         }
 
         // Install default configuration of the module.
-        $config_installer = \Drupal::service('config.installer');
         if ($sync_status) {
-          $config_installer
+          $this->configInstaller
             ->setSyncing(TRUE)
             ->setSourceStorage($source_storage);
         }
-        \Drupal::service('config.installer')->installDefaultConfig('module', $module);
+        $this->configInstaller->installDefaultConfig('module', $module);
 
         // If the module has no current updates, but has some that were
         // previously removed, set the version to the value of
@@ -258,28 +364,25 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
         // particular, this happens when installing Drupal via Drush, as the
         // 'translations' stream wrapper is provided by Interface Translation
         // module and is later used to import translations.
-        \Drupal::service('stream_wrapper_manager')->register();
+        $this->streamWrapperManager->register();
 
         // Update the theme registry to include it.
         drupal_theme_rebuild();
 
         // Modules can alter theme info, so refresh theme data.
-        // @todo ThemeHandler cannot be injected into ModuleHandler, since that
-        //   causes a circular service dependency.
-        // @see https://www.drupal.org/node/2208429
-        \Drupal::service('theme_handler')->refreshInfo();
+        $this->themeHandler->refreshInfo();
 
         // Allow the module to perform install tasks.
         $this->moduleHandler->invoke($module, 'install');
 
         // Record the fact that it was installed.
-        \Drupal::logger('system')->info('%module module installed.', array('%module' => $module));
+        $this->logger->info('%module module installed.', array('%module' => $module));
       }
     }
 
     // If any modules were newly installed, invoke hook_modules_installed().
     if (!empty($modules_installed)) {
-      \Drupal::service('router.builder')->setRebuildNeeded();
+      $this->routeBuilder->setRebuildNeeded();
       $this->moduleHandler->invokeAll('modules_installed', array($modules_installed));
     }
 
@@ -298,7 +401,8 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       return FALSE;
     }
 
-    $extension_config = \Drupal::configFactory()->getEditable('core.extension');
+    // Only process currently installed modules.
+    $extension_config = $this->configFactory->getEditable('core.extension');
     $installed_modules = $extension_config->get('module') ?: array();
     if (!$module_list = array_intersect_key($module_list, $installed_modules)) {
       // Nothing to do. All modules already uninstalled.
@@ -351,11 +455,10 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       // Clean up all entity bundles (including fields) of every entity type
       // provided by the module that is being uninstalled.
       // @todo Clean this up in https://www.drupal.org/node/2350111.
-      $entity_manager = \Drupal::entityManager();
-      foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) {
+      foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
         if ($entity_type->getProvider() == $module) {
-          foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) {
-            $entity_manager->onBundleDelete($bundle, $entity_type_id);
+          foreach (array_keys($this->entityManager->getBundleInfo($entity_type_id)) as $bundle) {
+            $this->entityManager->onBundleDelete($bundle, $entity_type_id);
           }
         }
       }
@@ -368,24 +471,24 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       $this->moduleHandler->invoke($module, 'uninstall');
 
       // Remove all configuration belonging to the module.
-      \Drupal::service('config.manager')->uninstall('module', $module);
+      $this->configManager->uninstall('module', $module);
 
       // Notify interested components that this module's entity types are being
       // deleted. For example, a SQL-based storage handler can use this as an
       // opportunity to drop the corresponding database tables.
       // @todo Clean this up in https://www.drupal.org/node/2350111.
-      foreach ($entity_manager->getDefinitions() as $entity_type) {
+      foreach ($this->entityManager->getDefinitions() as $entity_type) {
         if ($entity_type->getProvider() == $module) {
-          $entity_manager->onEntityTypeDelete($entity_type);
+          $this->entityManager->onEntityTypeDelete($entity_type);
         }
       }
 
       // Remove the schema.
       drupal_uninstall_schema($module);
 
-      // Remove the module's entry from the config. Don't check schema when
-      // uninstalling a module since we are only clearing a key.
-      \Drupal::configFactory()->getEditable('core.extension')->clear("module.$module")->save(TRUE);
+      // Remove the module's entry from the config.
+      $extension_config = $this->configFactory->getEditable('core.extension');
+      $extension_config->clear("module.$module")->save();
 
       // Update the module handler to remove the module.
       // The current ModuleHandler instance is obsolete with the kernel rebuild
@@ -403,7 +506,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       drupal_static_reset('system_rebuild_module_data');
 
       // Clear plugin manager caches.
-      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
+      $this->pluginCacheClearer->clearCachedDefinitions();
 
       // Update the kernel to exclude the uninstalled modules.
       $this->updateKernel($module_filenames);
@@ -412,17 +515,13 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       drupal_theme_rebuild();
 
       // Modules can alter theme info, so refresh theme data.
-      // @todo ThemeHandler cannot be injected into ModuleHandler, since that
-      //   causes a circular service dependency.
-      // @see https://www.drupal.org/node/2208429
-      \Drupal::service('theme_handler')->refreshInfo();
+      $this->themeHandler->refreshInfo();
 
-      \Drupal::logger('system')->info('%module module uninstalled.', array('%module' => $module));
+      $this->logger->info('%module module uninstalled.', array('%module' => $module));
 
-      $schema_store = \Drupal::keyValue('system.schema');
-      $schema_store->delete($module);
+      $this->keyValueFactory->get('system.schema')->delete($module);
     }
-    \Drupal::service('router.builder')->setRebuildNeeded();
+    $this->routeBuilder->setRebuildNeeded();
     drupal_get_installed_schema_version(NULL, TRUE);
 
     // Let other modules react.
@@ -492,8 +591,7 @@ protected function updateKernel($module_filenames) {
     $this->kernel->updateModules($module_filenames, $module_filenames);
     // After rebuilding the container we need to update the injected
     // dependencies.
-    $container = $this->kernel->getContainer();
-    $this->moduleHandler = $container->get('module_handler');
+    $this->updateDependencies($this->kernel->getContainer());
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Module/InstallUninstallTest.php b/core/modules/system/src/Tests/Module/InstallUninstallTest.php
index b26cb7c..b66b756 100644
--- a/core/modules/system/src/Tests/Module/InstallUninstallTest.php
+++ b/core/modules/system/src/Tests/Module/InstallUninstallTest.php
@@ -95,7 +95,7 @@ public function testInstallUninstall() {
         $this->assertModules(array($module_to_install), TRUE);
         $this->assertModuleTablesExist($module_to_install);
         $this->assertModuleConfig($module_to_install);
-        $this->assertLogMessage('system', "%module module installed.", array('%module' => $module_to_install), RfcLogLevel::INFO);
+        $this->assertLogMessage('modules', "%module module installed.", array('%module' => $module_to_install), RfcLogLevel::INFO);
       }
 
       // Uninstall the original module, and check appropriate
@@ -173,7 +173,7 @@ protected function assertSuccessfulUninstall($module, $package = 'Core') {
     // module was just uninstalled, since the {watchdog} table won't be there
     // anymore.)
     $this->assertText(t('hook_modules_uninstalled fired for @module', array('@module' => $module)));
-    $this->assertLogMessage('system', "%module module uninstalled.", array('%module' => $module), RfcLogLevel::INFO);
+    $this->assertLogMessage('modules', "%module module uninstalled.", array('%module' => $module), RfcLogLevel::INFO);
 
     // Check that the module's database tables no longer exist.
     $this->assertModuleTablesDoNotExist($module);
diff --git a/core/tests/Drupal/Tests/Core/DependencyInjection/UpdateDependenciesTraitTest.php b/core/tests/Drupal/Tests/Core/DependencyInjection/UpdateDependenciesTraitTest.php
new file mode 100644
index 0000000..d25405b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/DependencyInjection/UpdateDependenciesTraitTest.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\UpdateDependenciesTraitTest.
+ */
+
+namespace Drupal\Tests\Core\DependencyInjection;
+
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\DependencyInjection\UpdateDependenciesTrait
+ * @group DependencyInjection
+ */
+class UpdateDependenciesTraitTest extends UnitTestCase {
+
+  /**
+   * @covers ::updateDependencies
+   */
+  public function testUpdateDependencies() {
+    $service = new \StdClass();
+    $service->_serviceId = 'test_service';
+    $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+    $container->expects($this->any())
+      ->method('get')
+      ->with('test_service')
+      ->willReturn($service);
+
+    $trait = $this->getMockForTrait('Drupal\Core\DependencyInjection\UpdateDependenciesTrait');
+    $trait->dependency = clone $service;
+    $trait->container = clone $container;
+    $object = new \StdClass();
+    $trait->object = $object;
+
+    $update_dependencies_method = new \ReflectionMethod($trait, 'updateDependencies');
+    $update_dependencies_method->setAccessible(TRUE);
+
+    // Ensure that the service and container are updated but other objects are
+    // untouched.
+    $update_dependencies_method->invoke($trait, $container);
+    $this->assertSame($service, $trait->dependency);
+    $this->assertSame($container, $trait->container);
+    $this->assertSame($object, $trait->object);
+  }
+
+}
