diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 420b092..8d3c57b 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -1619,6 +1619,9 @@ function theme_menu_link(array $variables) {
  */
 function theme_menu_local_task($variables) {
   $link = $variables['element']['#link'];
+  $link += array(
+    'localized_options' => array(),
+  );
   $link_text = $link['title'];
 
   if (!empty($variables['element']['#active'])) {
@@ -1865,8 +1868,8 @@ function menu_local_tasks($level = 0) {
   $data = &drupal_static(__FUNCTION__);
   $root_path = &drupal_static(__FUNCTION__ . ':root_path', '');
   $empty = array(
-    'tabs' => array('count' => 0, 'output' => array()),
-    'actions' => array('count' => 0, 'output' => array()),
+    'tabs' => array(),
+    'actions' => array(),
     'root_path' => &$root_path,
   );
 
@@ -1918,8 +1921,7 @@ function menu_local_tasks($level = 0) {
     // Tab parenting may skip levels, so the number of parts in the path may not
     // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort).
     $depth = 1001;
-    $actions['count'] = 0;
-    $actions['output'] = array();
+    $actions = array();
     while (isset($children[$path])) {
       $tabs_current = array();
       $actions_current = array();
@@ -1956,6 +1958,7 @@ function menu_local_tasks($level = 0) {
               '#theme' => 'menu_local_task',
               '#link' => $link,
               '#active' => TRUE,
+              '#weight' => isset($link['weight']) ? $link['weight'] : NULL,
             );
             $next_path = $item['path'];
             $tab_count++;
@@ -1968,6 +1971,7 @@ function menu_local_tasks($level = 0) {
               $actions_current[] = array(
                 '#theme' => 'menu_local_action',
                 '#link' => $link,
+                '#weight' => isset($link['weight']) ? $link['weight'] : NULL,
               );
               $action_count++;
             }
@@ -1976,6 +1980,7 @@ function menu_local_tasks($level = 0) {
               $tabs_current[] = array(
                 '#theme' => 'menu_local_task',
                 '#link' => $link,
+                '#weight' => isset($link['weight']) ? $link['weight'] : NULL,
               );
               $tab_count++;
             }
@@ -1983,10 +1988,8 @@ function menu_local_tasks($level = 0) {
         }
       }
       $path = $next_path;
-      $tabs[$depth]['count'] = $tab_count;
-      $tabs[$depth]['output'] = $tabs_current;
-      $actions['count'] += $action_count;
-      $actions['output'] = array_merge($actions['output'], $actions_current);
+      $tabs[$depth] = $tabs_current;
+      $actions = array_merge($actions, $actions_current);
       $depth++;
     }
     $data['actions'] = $actions;
@@ -2032,6 +2035,7 @@ function menu_local_tasks($level = 0) {
               '#theme' => 'menu_local_task',
               '#link' => $link,
               '#active' => TRUE,
+              '#weight' => isset($link['weight']) ? $link['weight'] : NULL,
             );
             $next_path = $item['tab_parent'];
             if (isset($tasks[$next_path])) {
@@ -2042,14 +2046,14 @@ function menu_local_tasks($level = 0) {
             $tabs_current[] = array(
               '#theme' => 'menu_local_task',
               '#link' => $link,
+              '#weight' => isset($link['weight']) ? $link['weight'] : NULL,
             );
           }
         }
       }
       $path = $next_path;
       $parent = $next_parent;
-      $tabs[$depth]['count'] = $count;
-      $tabs[$depth]['output'] = $tabs_current;
+      $tabs[$depth] = $tabs_current;
       $depth--;
     }
     // Sort by depth.
@@ -2071,7 +2075,7 @@ function menu_local_tasks($level = 0) {
   }
   // @todo If there are no tabs, then there still can be actions; for example,
   //   when added via hook_menu_local_tasks_alter().
-  elseif (!empty($data['actions']['output'])) {
+  elseif (!empty($data['actions'])) {
     return array('actions' => $data['actions']) + $empty;
   }
   return $empty;
@@ -2184,7 +2188,7 @@ function menu_contextual_links($module, $parent_path, $args) {
 function menu_primary_local_tasks() {
   $links = menu_local_tasks(0);
   // Do not display single tabs.
-  return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : '');
+  return count($links['tabs']) > 1 ? $links['tabs'] : '';
 }
 
 /**
@@ -2193,7 +2197,7 @@ function menu_primary_local_tasks() {
 function menu_secondary_local_tasks() {
   $links = menu_local_tasks(1);
   // Do not display single tabs.
-  return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : '');
+  return count($links['tabs']) > 1 ? $links['tabs'] : '';
 }
 
 /**
@@ -2201,7 +2205,7 @@ function menu_secondary_local_tasks() {
  */
 function menu_local_actions() {
   $links = menu_local_tasks();
-  return $links['actions']['output'];
+  return $links['actions'];
 }
 
 /**
@@ -3537,7 +3541,6 @@ function _menu_router_build($callbacks) {
     $item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions);
     $item += array(
       'title' => '',
-      'weight' => 0,
       'type' => MENU_NORMAL_ITEM,
       'module' => '',
       '_number_parts' => $number_parts,
@@ -3545,6 +3548,9 @@ function _menu_router_build($callbacks) {
       '_fit' => $fit,
     );
     $item += array(
+      // Default MENU_DEFAULT_LOCAL_TASKs to a weight of -10, so they appear as
+      // first tab by default.
+      'weight' => ($item['type'] & MENU_DEFAULT_LOCAL_TASK) == MENU_DEFAULT_LOCAL_TASK ? -10 : 0,
       '_visible' => (bool) ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
       '_tab' => (bool) ($item['type'] & MENU_IS_LOCAL_TASK),
     );
diff --git a/core/includes/module.inc b/core/includes/module.inc
index d9eab10..6a1e859 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -31,7 +31,7 @@ function module_load_all($bootstrap = FALSE) {
   $has_run = &$drupal_static_fast['has_run'];
 
   if (isset($bootstrap)) {
-    $type = $bootstrap ? 'bootstrap' : 'module_enabled';
+    $type = $bootstrap ? 'bootstrap' : 'module';
     foreach (module_list($type) as $module) {
       drupal_load('module', $module);
     }
@@ -54,7 +54,7 @@ function module_load_all($bootstrap = FALSE) {
  *
  * @param string $type
  *   The type of list to return:
- *   - module_enabled: All enabled modules.
+ *   - module: All enabled modules.
  *   - bootstrap: All enabled modules required for bootstrap.
  * @param array $fixed_list
  *   (optional) An array of module names to override the list of modules. This
@@ -66,7 +66,7 @@ function module_load_all($bootstrap = FALSE) {
  *   An associative array whose keys and values are the names of the modules in
  *   the list.
  */
-function module_list($type = 'module_enabled', array $fixed_list = NULL) {
+function module_list($type = 'module', array $fixed_list = NULL) {
   // This static is only used for $fixed_list.
   $module_list = &drupal_static(__FUNCTION__);
 
@@ -102,13 +102,13 @@ function module_list_reset() {
  *
  * @param $type
  *   The type of list to return:
- *   - module_enabled: All enabled modules.
+ *   - module: All enabled modules.
  *   - bootstrap: All enabled modules required for bootstrap.
- *   - theme: All themes.
+ *   - theme: All enabled themes.
  *
  * @return
  *   An associative array of modules or themes, keyed by name. For $type
- *   'bootstrap' and 'module_enabled', the array values equal the keys.
+ *   'bootstrap' and 'module', the array values equal the keys.
  *   For $type 'theme', the array values are objects representing the
  *   respective database row, with the 'info' property already unserialized.
  *
@@ -144,13 +144,13 @@ function system_list($type) {
     $lists['bootstrap'] = array_keys($bootstrap_list);
   }
   // Otherwise build the list for enabled modules and themes.
-  elseif (!isset($lists['module_enabled'])) {
+  elseif (!isset($lists['module'])) {
     if ($cached = cache('bootstrap')->get('system_list')) {
       $lists = $cached->data;
     }
-    else {
+    if (!isset($lists[$type])) {
       $lists = array(
-        'module_enabled' => array(),
+        'module' => array(),
         'theme' => array(),
         'filepaths' => array(),
       );
@@ -159,11 +159,11 @@ function system_list($type) {
       // Drupal installations, which might have modules installed in different
       // locations in the file system. The ordering here must also be
       // consistent with the one used in module_implements().
-      $result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC");
+      $result = db_query("SELECT * FROM {system} WHERE (type = 'theme' OR type = 'module') AND status = 1 ORDER BY weight ASC, name ASC");
       foreach ($result as $record) {
         // Build a list of all enabled modules.
         if ($record->type == 'module') {
-          $lists['module_enabled'][$record->name] = $record->name;
+          $lists['module'][$record->name] = $record->name;
         }
         // Build a list of themes.
         if ($record->type == 'theme') {
@@ -171,9 +171,7 @@ function system_list($type) {
           $lists['theme'][$record->name] = $record;
         }
         // Build a list of filenames so drupal_get_filename can use it.
-        if ($record->status) {
-          $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename);
-        }
+        $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename);
       }
       foreach ($lists['theme'] as $key => $theme) {
         if (!empty($theme->info['base theme'])) {
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2550fe8..47b022e 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -37,6 +37,34 @@
  */
 
 /**
+ * Loads a theme.
+ *
+ * @param string $name
+ *   The name of a theme to load.
+ *
+ * @return
+ *   The loaded theme object for $name, or FALSE if the passed $name does not
+ *   exist or is not enabled.
+ */
+function theme_load($name) {
+  $themes = list_themes();
+  if (isset($themes[$name]) && drupal_theme_access($themes[$name])) {
+    return $themes[$name];
+  }
+  return FALSE;
+}
+
+/**
+ * Menu title callback; Returns the sanitized human-readable name of a theme.
+ *
+ * @param $theme
+ *   The theme object to return the title for.
+ */
+function _theme_menu_title($theme) {
+  return check_plain($theme->info['name']);
+}
+
+/**
  * Determines if a theme is available to use.
  *
  * @param $theme
@@ -47,11 +75,18 @@
  *   FALSE otherwise.
  */
 function drupal_theme_access($theme) {
+  // Early-return for potentially bogus '0', FALSE, or NULL values.
+  if (empty($theme)) {
+    return FALSE;
+  }
   if (is_object($theme)) {
     return !empty($theme->status);
   }
   else {
     $themes = list_themes();
+    if (!isset($themes[$theme])) {
+      return FALSE;
+    }
     return !empty($themes[$theme]->status);
   }
 }
@@ -643,14 +678,14 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
  *     declare this theme as their base theme.
 */
 function list_themes($refresh = FALSE) {
-  $list = &drupal_static(__FUNCTION__, array());
+  $list = &drupal_static(__FUNCTION__);
 
   if ($refresh) {
-    $list = array();
+    $list = NULL;
     system_list_reset();
   }
 
-  if (empty($list)) {
+  if (!isset($list)) {
     $list = array();
     $themes = array();
     // Extract from the database only when it is available.
@@ -1404,7 +1439,6 @@ function theme_enable($theme_list) {
   }
 
   list_themes(TRUE);
-  menu_router_rebuild();
   drupal_theme_rebuild();
 
   // Invoke hook_themes_enabled() after the themes have been enabled.
@@ -1437,7 +1471,6 @@ function theme_disable($theme_list) {
   }
 
   list_themes(TRUE);
-  menu_router_rebuild();
   drupal_theme_rebuild();
 
   // Invoke hook_themes_disabled after the themes have been disabled.
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 869d4ee..b0a7947 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -45,7 +45,7 @@ public function registerBundles() {
 
     // @todo Remove the necessity of calling system_list() to find out which
     // bundles exist. See http://drupal.org/node/1331486
-    $modules = array_keys(system_list('module_enabled'));
+    $modules = array_keys(system_list('module'));
     foreach ($modules as $module) {
       $camelized = ContainerBuilder::camelize($module);
       $class = "Drupal\\{$module}\\{$camelized}Bundle";
diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index 848298f..d573ffb 100644
--- a/core/modules/block/block.admin.inc
+++ b/core/modules/block/block.admin.inc
@@ -33,6 +33,9 @@ function block_admin_display($theme = NULL) {
     // If theme is not specifically set, rehash for the current theme.
     $theme = $theme_key;
   }
+  elseif (is_object($theme)) {
+    $theme = $theme->name;
+  }
 
   // Fetch and sort blocks.
   $blocks = block_admin_display_prepare_blocks($theme);
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 0626c08..b676169 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -62,11 +62,21 @@ function block_help($path, $arg) {
     case 'admin/structure/block/add':
       return '<p>' . t('Use this page to create a new custom block.') . '</p>';
   }
-  if ($arg[0] == 'admin' && $arg[1] == 'structure' && $arg['2'] == 'block' && (empty($arg[3]) || $arg[3] == 'list')) {
-    $demo_theme = !empty($arg[4]) ? $arg[4] : variable_get('theme_default', 'stark');
-    $themes = list_themes();
+
+  if ($arg[0] === 'admin' && $arg[1] === 'structure' && $arg['2'] === 'block' && (empty($arg[3]) || $arg[3] === 'list')) {
     $output = '<p>' . t('This page provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions. Since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis. Remember that your changes will not be saved until you click the <em>Save blocks</em> button at the bottom of the page. Click the <em>configure</em> link next to each block to configure its specific title and visibility settings.') . '</p>';
-    $output .= '<p>' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '</p>';
+    if (!empty($arg[4])) {
+      if (drupal_theme_access($arg[4])) {
+        $demo_theme = $arg[4];
+      }
+    }
+    else {
+      $demo_theme = variable_get('theme_default', 'stark');
+    }
+    if (isset($demo_theme)) {
+      $themes = list_themes();
+      $output .= '<p>' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '</p>';
+    }
     return $output;
   }
 }
@@ -103,12 +113,10 @@ function block_permission() {
  * Implements hook_menu().
  */
 function block_menu() {
-  $default_theme = variable_get('theme_default', 'stark');
   $items['admin/structure/block'] = array(
     'title' => 'Blocks',
     'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
     'page callback' => 'block_admin_display',
-    'page arguments' => array($default_theme),
     'access arguments' => array('administer blocks'),
     'file' => 'block.admin.inc',
   );
@@ -141,39 +149,86 @@ function block_menu() {
     'type' => MENU_LOCAL_ACTION,
     'file' => 'block.admin.inc',
   );
-  foreach (list_themes() as $key => $theme) {
-    $items['admin/structure/block/list/' . $key] = array(
-      'title' => check_plain($theme->info['name']),
-      'page arguments' => array($key),
-      'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
-      'weight' => $key == $default_theme ? -10 : 0,
-      'access callback' => '_block_themes_access',
-      'access arguments' => array($key),
-      'file' => 'block.admin.inc',
-    );
-    if ($key != $default_theme) {
-      $items['admin/structure/block/list/' . $key . '/add'] = array(
-        'title' => 'Add block',
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('block_add_block_form'),
-        'access arguments' => array('administer blocks'),
-        'type' => MENU_LOCAL_ACTION,
-        'file' => 'block.admin.inc',
+
+  $items['admin/structure/block/list/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/block/list/%theme'] = array(
+    'title' => 'Theme blocks',
+    'title callback' => '_theme_menu_title',
+    'title arguments' => array(4),
+    'page callback' => 'block_admin_display',
+    'page arguments' => array(4),
+    'type' => MENU_LOCAL_TASK,
+    'access callback' => '_block_themes_access',
+    'access arguments' => array(4),
+    'file' => 'block.admin.inc',
+  );
+  $items['admin/structure/block/list/%theme/add'] = array(
+    'title' => 'Add block',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('block_add_block_form'),
+    'access arguments' => array('administer blocks'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'block.admin.inc',
+  );
+  $items['admin/structure/block/demo/%theme'] = array(
+    'title' => 'Theme block region demo',
+    'title callback' => '_theme_menu_title',
+    'title arguments' => array(4),
+    'page callback' => 'block_admin_demo',
+    'page arguments' => array(4),
+    'type' => MENU_CALLBACK,
+    'access callback' => '_block_themes_access',
+    'access arguments' => array(4),
+    'theme callback' => '_block_custom_theme',
+    'theme arguments' => array(4),
+    'file' => 'block.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_menu_local_tasks_alter().
+ */
+function block_menu_local_tasks_alter(&$data, $router_item, $root_path) {
+  if ($root_path == 'admin/structure/block' || strpos($root_path, 'admin/structure/block/list') === 0) {
+    // Replace the tab title of the default local task with the name of the
+    // default theme.
+    $themes = list_themes();
+    $default_theme = variable_get('theme_default', 'stark');
+    foreach ($data['tabs'][0] as &$tab) {
+      if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'admin/structure/block/list/list') {
+        $tab['#link']['title'] = $themes[$default_theme]->info['name'];
+      }
+    }
+
+    // "Expand" the dynamic %theme argument into a tab for each theme.
+    $selected_theme = isset($router_item['original_map'][4]) ? $router_item['original_map'][4] : NULL;
+    foreach ($themes as $theme) {
+      // The default theme is always exposed as default local task already.
+      if ($theme->name === $default_theme) {
+        continue;
+      }
+      // If the current page shows the interface for a selected theme, then the
+      // menu router item with the %theme argument will expose the selected
+      // theme already; do not duplicate that tab.
+      if ($theme->name === $selected_theme) {
+        continue;
+      }
+      $data['tabs'][0][] = array(
+        '#theme' => 'menu_local_task',
+        '#link' => array(
+          'title' => $theme->info['name'],
+          'href' => 'admin/structure/block/list/' . $theme->name,
+        ),
+        '#active' => $theme->name === $selected_theme,
+        '#weight' => $theme->name === $default_theme ? -10 : 0,
       );
     }
-    $items['admin/structure/block/demo/' . $key] = array(
-      'title' => check_plain($theme->info['name']),
-      'page callback' => 'block_admin_demo',
-      'page arguments' => array($key),
-      'type' => MENU_CALLBACK,
-      'access callback' => '_block_themes_access',
-      'access arguments' => array($key),
-      'theme callback' => '_block_custom_theme',
-      'theme arguments' => array($key),
-      'file' => 'block.admin.inc',
-    );
   }
-  return $items;
 }
 
 /**
@@ -208,7 +263,9 @@ function _block_themes_access($theme) {
 function _block_custom_theme($theme = NULL) {
   // We return exactly what was passed in, to guarantee that the page will
   // always be displayed using the theme whose blocks are being configured.
-  return $theme;
+  if (isset($theme->name)) {
+    return $theme->name;
+  }
 }
 
 /**
@@ -412,6 +469,10 @@ function _block_rehash($theme = NULL) {
   }
   $regions = system_region_list($theme);
 
+  if (is_object($theme)) {
+    $theme = $theme->name;
+  }
+
   // These are the blocks the function will return.
   $blocks = array();
   // These are the blocks defined by code and modified by the database.
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
index c3a220f..e80a053 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
@@ -39,7 +39,7 @@ function testAdminTheme() {
 
     // Ensure that access to block admin page is denied when theme is disabled.
     $this->drupalGet('admin/structure/block/list/bartik');
-    $this->assertResponse(403);
+    $this->assertResponse(404);
 
     // Enable admin theme and confirm that tab is accessible.
     theme_enable(array('bartik'));
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
index 13a78af..ec48abe 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
@@ -65,7 +65,7 @@ function testBlockNotInHiddenRegion() {
     $theme = 'block_test_theme';
     theme_enable(array($theme));
     variable_set('theme_default', $theme);
-    menu_router_rebuild();
+    menu_cache_clear_all();
 
     // Ensure that "block_test_theme" is set as the default theme.
     $this->drupalGet('admin/structure/block');
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
index 40edfa5..cc874d2 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageDisplayTest.php
@@ -14,13 +14,6 @@
  */
 class ManageDisplayTest extends FieldUiTestBase {
 
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('search');
-
   public static function getInfo() {
     return array(
       'name' => 'Manage display',
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 30b1e6b..938cdb9 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -209,7 +209,7 @@ function forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
           );
         }
       }
-      $data['actions']['output'] = array_merge($data['actions']['output'], $links);
+      $data['actions'] = array_merge($data['actions'], $links);
     }
   }
 }
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 53e5417..d459cf7 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1995,7 +1995,7 @@ function node_menu_local_tasks_alter(&$data, $router_item, $root_path) {
   if ($root_path == 'admin/content') {
     $item = menu_get_item('node/add');
     if ($item['access']) {
-      $data['actions']['output'][] = array(
+      $data['actions'][] = array(
         '#theme' => 'menu_local_action',
         '#link' => $item,
       );
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
index 278b1e0..517dbfe 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
@@ -120,6 +120,7 @@ function testShortcutLinkDelete() {
    */
   function testNoShortcutLink() {
     // Change to a theme that displays shortcuts.
+    theme_enable(array('seven'));
     variable_set('theme_default', 'seven');
 
     $this->drupalGet('page-that-does-not-exist');
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 9654f9c..71c040d 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -690,6 +690,8 @@ protected function prepareEnvironment() {
     $this->originalContainer = clone drupal_container();
     $this->originalLanguage = $language_interface;
     $this->originalConfigDirectories = $GLOBALS['config_directories'];
+    $this->originalThemeKey = $GLOBALS['theme_key'];
+    $this->originalTheme = $GLOBALS['theme'];
 
     // Save further contextual information.
     $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
@@ -735,6 +737,10 @@ protected function prepareEnvironment() {
       $this->configDirectories[$type] = $this->originalFileDirectory . '/' . $path;
     }
 
+    // Unset globals.
+    unset($GLOBALS['theme_key']);
+    unset($GLOBALS['theme']);
+
     // Log fatal errors.
     ini_set('log_errors', 1);
     ini_set('error_log', $this->public_files_directory . '/error.log');
@@ -778,6 +784,10 @@ protected function tearDown() {
     Database::removeConnection('default');
     Database::renameConnection('simpletest_original_default', 'default');
 
+    // Restore original globals.
+    $GLOBALS['theme_key'] = $this->originalThemeKey;
+    $GLOBALS['theme'] = $this->originalTheme;
+
     // Reset all static variables.
     drupal_static_reset();
 
diff --git a/core/modules/statistics/statistics.php b/core/modules/statistics/statistics.php
index 87e3dae..b6cedf3 100644
--- a/core/modules/statistics/statistics.php
+++ b/core/modules/statistics/statistics.php
@@ -9,16 +9,15 @@
 chdir('../../..');
 
 /**
-* Root directory of Drupal installation.
-*/
+ * Root directory of Drupal installation.
+ */
 define('DRUPAL_ROOT', getcwd());
 
 include_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
 
-if (config('statistics.settings')->get('count_content_views')) {
-  $nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
-  if ($nid) {
+if ($nid = (int) $_POST['nid']) {
+  if (config('statistics.settings')->get('count_content_views')) {
     db_merge('node_counter')
       ->key(array('nid' => $nid))
       ->fields(array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php b/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php
index 9db8518..7c77745 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Batch/PageTest.php
@@ -35,8 +35,8 @@ public static function getInfo() {
   function testBatchProgressPageTheme() {
     // Make sure that the page which starts the batch (an administrative page)
     // is using a different theme than would normally be used by the batch API.
+    theme_enable(array('bartik', 'seven'));
     variable_set('theme_default', 'bartik');
-    theme_enable(array('seven'));
     variable_set('admin_theme', 'seven');
     // Log in as an administrator who can see the administrative theme.
     $admin_user = $this->drupalCreateUser(array('view the administration theme'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php
index 9bdeac4..c8bc3a4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/InfoAlterTest.php
@@ -30,6 +30,7 @@ function testSystemInfoAlter() {
     // Enable our test module. Flush all caches, which we assert is the only
     // thing necessary to use the rebuilt {system}.info.
     module_enable(array('module_test'), FALSE);
+    theme_enable(array('seven'));
     $this->resetAll();
     $this->assertTrue(module_exists('module_test'), t('Test module is enabled.'));
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
index 3d0188d..e675843 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
@@ -206,7 +206,7 @@ function testAdministrationTheme() {
     $this->assertRaw('core/themes/stark', t('Site default theme used on the add content page.'));
 
     // Reset to the default theme settings.
-    variable_set('theme_default', 'bartik');
+    variable_set('theme_default', 'stark');
     $edit = array(
       'admin_theme' => '0',
       'node_admin_theme' => FALSE,
@@ -214,10 +214,10 @@ function testAdministrationTheme() {
     $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
 
     $this->drupalGet('admin');
-    $this->assertRaw('core/themes/bartik', t('Site default theme used on administration page.'));
+    $this->assertRaw('core/themes/stark', t('Site default theme used on administration page.'));
 
     $this->drupalGet('node/add');
-    $this->assertRaw('core/themes/bartik', t('Site default theme used on the add content page.'));
+    $this->assertRaw('core/themes/stark', t('Site default theme used on the add content page.'));
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
index 484d00b..98da0ca 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
@@ -141,18 +141,20 @@ function testTemplateOverride() {
    * Test the list_themes() function.
    */
   function testListThemes() {
+    theme_enable(array('test_subtheme'));
     $themes = list_themes();
     // Check if drupal_theme_access() retrieves enabled themes properly from list_themes().
     $this->assertTrue(drupal_theme_access('test_theme'), t('Enabled theme detected'));
-    // Check if list_themes() returns disabled themes.
-    $this->assertTrue(array_key_exists('test_basetheme', $themes), t('Disabled theme detected'));
+
     // Check for base theme and subtheme lists.
     $base_theme_list = array('test_basetheme' => 'Theme test base theme');
     $sub_theme_list = array('test_subtheme' => 'Theme test subtheme');
     $this->assertIdentical($themes['test_basetheme']->sub_themes, $sub_theme_list, t('Base theme\'s object includes list of subthemes.'));
     $this->assertIdentical($themes['test_subtheme']->base_themes, $base_theme_list, t('Subtheme\'s object includes list of base themes.'));
+
     // Check for theme engine in subtheme.
     $this->assertIdentical($themes['test_subtheme']->engine, 'phptemplate', t('Subtheme\'s object includes the theme engine.'));
+
     // Check for theme engine prefix.
     $this->assertIdentical($themes['test_basetheme']->prefix, 'phptemplate', t('Base theme\'s object includes the theme engine prefix.'));
     $this->assertIdentical($themes['test_subtheme']->prefix, 'phptemplate', t('Subtheme\'s object includes the theme engine prefix.'));
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 2bf4343..b1967d6 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -280,12 +280,10 @@ function system_themes_admin_form_submit($form, &$form_state) {
 function system_theme_enable() {
   if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) {
     $theme = $_REQUEST['theme'];
-    // Get current list of themes.
-    $themes = list_themes();
-
     // Check if the specified theme is one recognized by the system.
-    if (!empty($themes[$theme])) {
+    if (drupal_get_path('theme', $theme)) {
       theme_enable(array($theme));
+      $themes = list_themes();
       drupal_set_message(t('The %theme theme has been enabled.', array('%theme' => $themes[$theme]->info['name'])));
     }
     else {
@@ -330,26 +328,17 @@ function system_theme_disable() {
 function system_theme_default() {
   if (isset($_REQUEST['theme']) && isset($_REQUEST['token']) && drupal_valid_token($_REQUEST['token'], 'system-theme-operation-link')) {
     $theme = $_REQUEST['theme'];
-    // Get current list of themes.
-    $themes = list_themes();
-
     // Check if the specified theme is one recognized by the system.
-    if (!empty($themes[$theme])) {
+    if (drupal_get_path('theme', $theme)) {
+      $themes = list_themes();
       // Enable the theme if it is currently disabled.
-      if (empty($themes[$theme]->status)) {
-       theme_enable(array($theme));
+      if (!isset($themes[$theme])) {
+        theme_enable(array($theme));
+        $themes = list_themes();
       }
       // Set the default theme.
       variable_set('theme_default', $theme);
 
-      // Rebuild the menu. This duplicates the menu_router_rebuild() in
-      // theme_enable(). However, modules must know the current default theme in
-      // order to use this information in hook_menu() or hook_menu_alter()
-      // implementations, and doing the variable_set() before the theme_enable()
-      // could result in a race condition where the theme is default but not
-      // enabled.
-      menu_router_rebuild();
-
       // The status message depends on whether an admin theme is currently in use:
       // a value of 0 means the admin theme is set to be the default theme.
       $admin_theme = variable_get('admin_theme', 0);
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 9ffc73b..4ba6ea1 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -980,17 +980,10 @@ function hook_menu_link_delete($link) {
  *
  * @param $data
  *   An associative array containing:
- *   - actions: An associative array containing:
- *     - count: The amount of actions determined by the menu system, which can
- *       be ignored.
- *     - output: A list of of actions, each one being an associative array
- *       as described above.
- *   - tabs: An indexed array (list) of tab levels (up to 2 levels), each
- *     containing an associative array:
- *     - count: The amount of tabs determined by the menu system. This value
- *       does not need to be altered if there is more than one tab.
- *     - output: A list of of tabs, each one being an associative array as
- *       described above.
+ *   - actions: A list of of actions, each one being an associative array
+ *     as described above.
+ *   - tabs: A list of (up to 2) tab levels that contain a list of of tabs, each
+ *     one being an associative array as described above.
  * @param $router_item
  *   The menu system router item of the page.
  * @param $root_path
@@ -998,7 +991,7 @@ function hook_menu_link_delete($link) {
  */
 function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
   // Add an action linking to node/add to all pages.
-  $data['actions']['output'][] = array(
+  $data['actions'][] = array(
     '#theme' => 'menu_local_task',
     '#link' => array(
       'title' => t('Add new content'),
@@ -1012,7 +1005,7 @@ function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
   );
 
   // Add a tab linking to node/add to all pages.
-  $data['tabs'][0]['output'][] = array(
+  $data['tabs'][0][] = array(
     '#theme' => 'menu_local_task',
     '#link' => array(
       'title' => t('Example tab'),
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f78f123..2a5cdd6 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2736,6 +2736,7 @@ function system_get_info($type, $name = NULL) {
     }
   }
   else {
+    // @todo Migrate theme info to ModuleInfo implementation.
     $list = system_list($type);
     foreach ($list as $shortname => $item) {
       if (!empty($item->status)) {
@@ -2761,6 +2762,8 @@ function system_get_info($type, $name = NULL) {
  *   returned.
  *
  * @see Drupal\Core\Utility\ModuleInfo
+ *
+ * @todo Merge this helper entirely into system_get_info()?
  */
 function system_get_module_info($property) {
   static $info;
@@ -3095,25 +3098,26 @@ function _system_default_theme_features() {
 /**
  * Get a list of available regions from a specified theme.
  *
- * @param $theme_key
- *   The name of a theme.
+ * @param $theme
+ *   A theme object, or the name of a theme.
  * @param $show
  *   Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
  *   regions.
  * @return
  *   An array of regions in the form $region['name'] = 'description'.
  */
-function system_region_list($theme_key, $show = REGIONS_ALL) {
-  $themes = list_themes();
-  if (!isset($themes[$theme_key])) {
-    return array();
+function system_region_list($theme, $show = REGIONS_ALL) {
+  if (!is_object($theme)) {
+    $themes = list_themes();
+    if (!isset($themes[$theme])) {
+      return array();
+    }
+    $theme = $themes[$theme];
   }
-
   $list = array();
-  $info = $themes[$theme_key]->info;
   // If requested, suppress hidden regions. See block_admin_display_form().
-  foreach ($info['regions'] as $name => $label) {
-    if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
+  foreach ($theme->info['regions'] as $name => $label) {
+    if ($show == REGIONS_ALL || !isset($theme->info['regions_hidden']) || !in_array($name, $theme->info['regions_hidden'])) {
       $list[$name] = t($label);
     }
   }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php
index b226970..6ab0e74 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/ThemeTest.php
@@ -25,8 +25,8 @@ function setUp() {
 
     // Make sure we are using distinct default and administrative themes for
     // the duration of these tests.
+    theme_enable(array('bartik', 'seven'));
     variable_set('theme_default', 'bartik');
-    theme_enable(array('seven'));
     variable_set('admin_theme', 'seven');
 
     // Create and log in as a user who has permission to add and edit taxonomy
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 32221b3..e693aee 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -401,9 +401,6 @@ function standard_install() {
   );
   menu_link_save($item);
 
-  // Update the menu router information.
-  menu_router_rebuild();
-
   // Enable the admin theme.
   db_update('system')
     ->fields(array('status' => 1))
