diff --git a/core/core.services.yml b/core/core.services.yml
index 6f8cce6..4d6d9fe 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -152,6 +152,14 @@ services:
     calls:
       - [addSubscriber, ['@http_client_simpletest_subscriber']]
       - [setUserAgent, ['Drupal (+http://drupal.org/)']]
+  theme.negotiator:
+    class: Drupal\Core\Theme\ThemeNegotiator
+    arguments: ['@request']
+  theme.negotiator.default:
+    class: Drupal\Core\Theme\DefaultNegotiator
+    arguments: ['@config.factory']
+    tags:
+      - { name: theme_negotiator, priority: 100 }
   container.namespaces:
     class: ArrayObject
     arguments: [ '%container.namespaces%' ]
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 7bff76e..c686cdb 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -92,16 +92,24 @@ function drupal_theme_initialize() {
   }
 
   drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
-  $themes = list_themes();
-
   // Only select the user selected theme if it is available in the
   // list of themes that can be accessed.
-  $theme = !empty($user->theme) && drupal_theme_access($user->theme) ? $user->theme : config('system.theme')->get('default');
+  $themes = list_themes();
 
+  // @todo Let the theme.negotiator listen to the kernel request event.
+  $request = Drupal::request();
+  Drupal::service('theme.negotiator')->determineActiveTheme($request);
+
+  // @todo Convert to a theme negotiator.
+  //   service.
   // Allow modules to override the theme. Validation has already been performed
   // inside menu_get_custom_theme(), so we do not need to check it again here.
   $custom_theme = menu_get_custom_theme();
-  $theme = !empty($custom_theme) ? $custom_theme : $theme;
+  if ($custom_theme) {
+    $request->attributes->set('_theme_active', $custom_theme);
+  }
+
+  $theme = $request->attributes->get('_theme_active');
 
   // Store the identifier for retrieving theme settings with.
   $theme_key = $theme;
@@ -116,7 +124,7 @@ function drupal_theme_initialize() {
   _drupal_theme_initialize($themes[$theme], array_reverse($base_theme));
 
   // Themes can have alter functions, so reset the drupal_alter() cache.
-  drupal_static_reset('drupal_alter');
+  Drupal::moduleHandler()->resetImplementations();
 }
 
 /**
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index a6cb957..c3c6df5 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -22,6 +22,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterTwigExtensionsPass;
+use Drupal\Core\Theme\ThemeNegotiatorPass;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\DependencyInjection\Definition;
@@ -68,6 +69,9 @@ public function register(ContainerBuilder $container) {
     // Add the compiler pass that will process the tagged breadcrumb builder
     // services.
     $container->addCompilerPass(new RegisterBreadcrumbBuilderPass());
+    // Add the compiler pass that will process the tagged theme negotiator
+    // service.
+    $container->addCompilerPass(new ThemeNegotiatorPass());
     // Add the compiler pass that lets service providers modify existing
     // service definitions.
     $container->addCompilerPass(new ModifyServiceDefinitionsPass());
diff --git a/core/lib/Drupal/Core/Theme/DefaultNegotiator.php b/core/lib/Drupal/Core/Theme/DefaultNegotiator.php
new file mode 100644
index 0000000..f155b0d
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/DefaultNegotiator.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\DefaultNegotiator.
+ */
+
+namespace Drupal\Core\Theme;
+
+use Drupal\Core\Config\ConfigFactory;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Determines the default theme of the site.
+ */
+class DefaultNegotiator implements ThemeNegotiatorInterface {
+
+  /**
+   * Constructs a DefaultNegotiator object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   The config factory.
+   */
+  public function __construct(ConfigFactory $config_factory) {
+    $this->config = $config_factory->get('system.theme');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function determineActiveTheme(Request $request) {
+    return $this->config->get('default');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Theme/ThemeNegotiator.php b/core/lib/Drupal/Core/Theme/ThemeNegotiator.php
new file mode 100644
index 0000000..392b385
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/ThemeNegotiator.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\ThemeNegotiator.
+ */
+
+namespace Drupal\Core\Theme;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines
+ */
+class ThemeNegotiator implements ThemeNegotiatorInterface {
+
+
+  /**
+   * Holds arrays of theme negotiators, keyed by priority.
+   *
+   * @var array
+   */
+  protected $negotiators = array();
+
+  /**
+   * Holds the array of theme negotiators sorted by priority.
+   *
+   * Set to NULL if the array needs to be re-calculated.
+   *
+   * @var array|NULL
+   */
+  protected $sortedNegotiators;
+
+  /**
+   * Constructs a ThemeNegotiator object.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The active request.
+   * @param \Drupal\Core\Theme\ActiveTheme $active_theme
+   *   The active theme service.
+   */
+  public function __construct(Request $request) {
+    $this->request = $request;
+
+    $this->determineActiveTheme($request);
+  }
+
+  /**
+   * Adds a active theme negotiation service.
+   *
+   * @param \Drupal\Core\Theme\ThemeNegotiatorInterface $negotiator
+   *   The theme negotiator to add.
+   * @param int $priority
+   *   Priority of the breadcrumb builder.
+   */
+  public function addNegotiator(ThemeNegotiatorInterface $negotiator, $priority) {
+    $this->negotiators[$priority][] = $negotiator;
+    // Force the negotiators to be re-sorted.
+    $this->sortedNegotiators = NULL;
+  }
+
+  /**
+   * Returns the sorted array of theme negotiators.
+   *
+   * @return array|\Drupal\Core\Theme\ThemeNegotiatorInterface[]
+   *   An array of breadcrumb builder objects.
+   */
+  protected function getSortedNegotiators() {
+    if (!isset($this->sortedNegotiators)) {
+      // Sort the negotiators according to priority.
+      krsort($this->negotiators);
+      // Merge nested negotiators from $this->negotiators into
+      // $this->sortedNegotiators.
+      $this->sortedNegotiators = array();
+      foreach ($this->negotiators as $builders) {
+        $this->sortedNegotiators = array_merge($this->sortedNegotiators, $builders);
+      }
+    }
+    return $this->sortedNegotiators;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function determineActiveTheme(Request $request) {
+    foreach ($this->getSortedNegotiators() as $negotiator) {
+      if (($active_theme = $negotiator->determineActiveTheme($request)) && $active_theme !== NULL) {
+        $request->attributes->set('_theme_active', $active_theme);
+      }
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php b/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php
new file mode 100644
index 0000000..9bb80b1
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/ThemeNegotiatorInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\ThemeNegotiatorInterface.
+ */
+
+namespace Drupal\Core\Theme;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines an interface for classes which determine the active theme.
+ */
+interface ThemeNegotiatorInterface {
+
+  /**
+   * Determine the active theme for the request.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The active request of the site.
+   *
+   * @return string|null
+   *   Returns the active theme name, else return NULL.
+   */
+  public function determineActiveTheme(Request $request);
+
+}
diff --git a/core/lib/Drupal/Core/Theme/ThemeNegotiatorPass.php b/core/lib/Drupal/Core/Theme/ThemeNegotiatorPass.php
new file mode 100644
index 0000000..480b152
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/ThemeNegotiatorPass.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\ThemeNegotiatorPass.
+ */
+
+namespace Drupal\Core\Theme;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Adds services to the theme negotiator service.
+ *
+ * @see \Drupal\Core\Theme\ThemeNegotiator
+ */
+class ThemeNegotiatorPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('theme.negotiator')) {
+      return;
+    }
+    $manager = $container->getDefinition('theme.negotiator');
+    foreach ($container->findTaggedServiceIds('theme_negotiator') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $manager->addMethodCall('addNegotiator', array(new Reference($id), $priority));
+    }
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Theme/UserNegotiator.php b/core/modules/user/lib/Drupal/user/Theme/UserNegotiator.php
new file mode 100644
index 0000000..185703b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Theme/UserNegotiator.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Theme\UserNegotiator.
+ */
+
+namespace Drupal\user\Theme;
+
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Theme\ActiveTheme;
+use Drupal\Core\Theme\ThemeNegotiatorInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines the theme negotiator service for theme configured per user.
+ */
+class UserNegotiator implements  ThemeNegotiatorInterface {
+
+  /**
+   * The user storage controller.
+   *
+   * @var \Drupal\user\UserStorageControllerInterface
+   */
+  protected $userStorageController;
+
+  /**
+   * Constructs a UserNegotiator object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->userStorageController = $entity_manager->getStorageController('user');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function determineActiveTheme(Request $request) {
+    if ($account = $request->attributes->get('account')) {;
+      if ($user = $this->userStorageController->load($account->id())) {;
+        // Only select the user selected theme if it is available in the
+        // list of themes that can be accessed.
+        if (!empty($user->theme) && drupal_theme_access($user->theme)) {
+          return $user->theme;
+        }
+      }
+    }
+  }
+
+}
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 6fb7d47..6b34ff6 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -25,3 +25,9 @@ services:
     class: Drupal\user\EventSubscriber\MaintenanceModeSubscriber
     tags:
       - { name: event_subscriber }
+  theme.negotiator.user:
+    class: Drupal\user\Theme\UserNegotiator
+    arguments: ['@plugin.manager.entity']
+    tags:
+      - { name: theme_negotiator }
+
diff --git a/core/modules/views/lib/Drupal/views/ViewExecutable.php b/core/modules/views/lib/Drupal/views/ViewExecutable.php
index 41d874e..d3a76bd 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -1277,7 +1277,6 @@ public function render($display_id = NULL) {
       return;
     }
 
-    drupal_theme_initialize();
     $config = config('views.settings');
 
     $exposed_form = $this->display_handler->getPlugin('exposed_form');
@@ -1341,11 +1340,13 @@ public function render($display_id = NULL) {
       $module_handler->invokeAll('views_pre_render', array($this));
 
       // Let the themes play too, because pre render is a very themey thing.
-      foreach ($GLOBALS['base_theme_info'] as $base) {
-        $module_handler->invoke($base, 'views_pre_render', array($this));
-      }
+      if (isset($GLOBALS['base_theme_info']) && isset($GLOBALS['theme'])) {
+        foreach ($GLOBALS['base_theme_info'] as $base) {
+          $module_handler->invoke($base, 'views_pre_render', array($this));
+        }
 
-      $module_handler->invoke($GLOBALS['theme'], 'views_pre_render', array($this));
+        $module_handler->invoke($GLOBALS['theme'], 'views_pre_render', array($this));
+      }
 
       $this->display_handler->output = $this->display_handler->render();
       if ($cache) {
@@ -1363,11 +1364,13 @@ public function render($display_id = NULL) {
     $module_handler->invokeAll('views_post_render', array($this, $this->display_handler->output, $cache));
 
     // Let the themes play too, because post render is a very themey thing.
-    foreach ($GLOBALS['base_theme_info'] as $base) {
-      $module_handler->invoke($base, 'views_post_render', array($this));
-    }
+    if (isset($GLOBALS['base_theme_info']) && isset($GLOBALS['theme'])) {
+      foreach ($GLOBALS['base_theme_info'] as $base) {
+        $module_handler->invoke($base, 'views_post_render', array($this));
+      }
 
-    $module_handler->invoke($GLOBALS['theme'], 'views_post_render', array($this));
+      $module_handler->invoke($GLOBALS['theme'], 'views_post_render', array($this));
+    }
 
     return $this->display_handler->output;
   }
