diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index e6403cf..3d492a0 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1502,6 +1502,7 @@ function theme_enable($theme_list) {
 
   \Drupal::service('router.builder')->rebuild();
   menu_router_rebuild();
+  \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
   drupal_theme_rebuild();
 
   // Invoke hook_themes_enabled() after the themes have been enabled.
@@ -1538,6 +1539,7 @@ function theme_disable($theme_list) {
   list_themes(TRUE);
   \Drupal::service('router.builder')->rebuild();
   menu_router_rebuild();
+  \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
   drupal_theme_rebuild();
 
   // Invoke hook_themes_disabled after the themes have been disabled.
diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
index ae1d083..ca8d9e8 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
@@ -154,6 +154,13 @@ public function onIframeUpload(GetResponseForControllerResultEvent $event) {
    */
   public function onHtml(GetResponseForControllerResultEvent $event) {
     $page_callback_result = $event->getControllerResult();
+    $request = $event->getRequest();
+
+    // If no title was returned fall back to one defined in the route.
+    if (!isset($page_callback_result['#title']) && $request->attributes->has('_title')) {
+      $page_callback_result['#title'] = $request->attributes->get('_title');
+    }
+
     return new Response(drupal_render_page($page_callback_result));
   }
 
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index a02b8bb..26f20a5 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -200,7 +200,7 @@ public function getLocalTasksForRoute($route_name) {
           'parents' => $parents,
           'children' => $children,
         );
-        $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, array('local_task'));
+        $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, $this->cacheTags);
       }
       // Create a plugin instance for each element of the hierarchy.
       foreach ($tab_root_ids as $root_id) {
diff --git a/core/modules/action/action.local_tasks.yml b/core/modules/action/action.local_tasks.yml
new file mode 100644
index 0000000..b8825e0
--- /dev/null
+++ b/core/modules/action/action.local_tasks.yml
@@ -0,0 +1,5 @@
+action.admin:
+  route_name: action.admin
+  title: 'Manage actions'
+  description: 'Manage the actions defined for your site.'
+  tab_root_id: action.admin
diff --git a/core/modules/action/action.module b/core/modules/action/action.module
index a1f2a14..de914a5 100644
--- a/core/modules/action/action.module
+++ b/core/modules/action/action.module
@@ -53,11 +53,6 @@ function action_menu() {
     'description' => 'Manage the actions defined for your site.',
     'route_name' => 'action.admin',
   );
-  $items['admin/config/system/actions/manage'] = array(
-    'title' => 'Manage actions',
-    'description' => 'Manage the actions defined for your site.',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
   $items['admin/config/system/actions/add'] = array(
     'title' => 'Create an advanced action',
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
diff --git a/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php b/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php
new file mode 100644
index 0000000..d882c77
--- /dev/null
+++ b/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\action\Tests\Menu\ActionLocalTasksTest
+ */
+
+namespace Drupal\action\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of action local tasks.
+ *
+ * @group Drupal
+ * @group Action
+ */
+class ActionLocalTasksTest extends LocalTaskIntegrationTest {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Action local tasks test',
+      'description' => 'Test action local tasks.',
+      'group' => 'Action',
+    );
+  }
+
+  public function setUp() {
+    $this->moduleList = array('action' => 'core/modules/action/action.info');
+    parent::setUp();
+  }
+
+  /**
+   * Test local task existence.
+   */
+  public function testActionLocalTasks() {
+    $this->assertLocalTasks('action.admin', array(array('action.admin')));
+  }
+}
diff --git a/core/modules/aggregator/aggregator.local_tasks.yml b/core/modules/aggregator/aggregator.local_tasks.yml
new file mode 100644
index 0000000..a626fef
--- /dev/null
+++ b/core/modules/aggregator/aggregator.local_tasks.yml
@@ -0,0 +1,37 @@
+aggregator.admin_overview:
+  route_name: aggregator.admin_overview
+  title: 'List'
+  tab_root_id: aggregator.admin_overview
+aggregator.admin_settings:
+  route_name: aggregator.admin_settings
+  title: 'Settings'
+  description: 'Configure the behavior of the feed aggregator, including when to discard feed items and how to present feed items and categories.'
+  weight: 100
+  tab_root_id: aggregator.admin_overview
+
+aggregator.category_view:
+  route_name: aggregator.category_view
+  tab_root_id: aggregator.category_view
+  title: 'View'
+aggregator.categorize_category_form:
+  route_name: aggregator.categorize_category_form
+  tab_root_id: aggregator.category_view
+  title: Categorize
+aggregator.category_edit:
+  route_name: aggregator.category_edit
+  tab_root_id: aggregator.category_view
+  title: Configure
+
+aggregator.feed_view:
+  route_name: aggregator.feed_view
+  tab_root_id: aggregator.feed_view
+  title: View
+aggregator.categorize_feed_form:
+  route_name: aggregator.categorize_feed_form
+  tab_root_id: aggregator.feed_view
+  title: 'Categorize'
+aggregator.feed_configure:
+  route_name: aggregator.feed_configure
+  tab_root_id: aggregator.feed_view
+  title: 'Configure'
+  weight: 10
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index c2da795..045c156 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -92,6 +92,7 @@ function aggregator_theme() {
  */
 function aggregator_menu() {
   $items['admin/config/services/aggregator'] = array(
+    'title' => 'Feed aggregator',
     'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.",
     'route_name' => 'aggregator.admin_overview',
     'weight' => 10,
@@ -119,17 +120,6 @@ function aggregator_menu() {
     'title' => 'Update items',
     'route_name' => 'aggregator.feed_refresh',
   );
-  $items['admin/config/services/aggregator/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/services/aggregator/settings'] = array(
-    'title' => 'Settings',
-    'description' => 'Configure the behavior of the feed aggregator, including when to discard feed items and how to present feed items and categories.',
-    'route_name' => 'aggregator.admin_settings',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 100,
-  );
   $items['aggregator'] = array(
     'title' => 'Feed aggregator',
     'weight' => 5,
@@ -148,41 +138,11 @@ function aggregator_menu() {
     'title arguments' => array(2),
     'route_name' => 'aggregator.category_view',
   );
-  $items['aggregator/categories/%aggregator_category/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['aggregator/categories/%aggregator_category/categorize'] = array(
-    'title' => 'Categorize',
-    'type' => MENU_LOCAL_TASK,
-    'route_name' => 'aggregator.categorize_category_form',
-  );
-  $items['aggregator/categories/%aggregator_category/configure'] = array(
-    'title' => 'Configure',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 10,
-    'route_name' => 'aggregator.category_edit',
-  );
   $items['aggregator/sources/%aggregator_feed'] = array(
     'title callback' => 'entity_page_label',
     'title arguments' => array(2),
     'route_name' => 'aggregator.feed_view',
   );
-  $items['aggregator/sources/%aggregator_feed/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['aggregator/sources/%aggregator_feed/categorize'] = array(
-    'title' => 'Categorize',
-    'route_name' => 'aggregator.categorize_feed_form',
-    'type' => MENU_LOCAL_TASK,
-  );
-  $items['aggregator/sources/%aggregator_feed/configure'] = array(
-    'title' => 'Configure',
-    'route_name' => 'aggregator.feed_configure',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 10,
-  );
   $items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
     'title' => 'Edit feed',
     'route_name' => 'aggregator.feed_edit',
diff --git a/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php b/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php
new file mode 100644
index 0000000..a5bb85b
--- /dev/null
+++ b/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\aggregator\Tests\Menu\AggregatorLocalTasksTest
+ */
+
+namespace Drupal\aggregator\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of aggregator local tasks.
+ *
+ * @group Drupal
+ * @group Aggregator
+ */
+class AggregatorLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Aggregator local tasks test',
+      'description' => 'Test existence of aggregator local tasks.',
+      'group' => 'Aggregator',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array('aggregator' => 'core/modules/aggregator/aggregator.info');
+    parent::setUp();
+  }
+
+  /**
+   * Test local task existence.
+   *
+   * @dataProvider getAggregatorAdminRoutes
+   */
+  public function testAggregatorAdminLocalTasks($route) {
+    $this->assertLocalTasks($route, array(
+      0 => array('aggregator.admin_overview', 'aggregator.admin_settings'),
+    ));
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getAggregatorAdminRoutes() {
+    return array(
+      array('aggregator.admin_overview'),
+      array('aggregator.admin_settings'),
+    );
+  }
+
+  /**
+   * Check category aggregator tasks.
+   *
+   * @dataProvider getAggregatorCategoryRoutes
+   */
+  public function testAggregatorCategoryLocalTasks($route) {
+    $this->assertLocalTasks($route, array(
+      0 => array('aggregator.category_view', 'aggregator.categorize_category_form', 'aggregator.category_edit'),
+    ));
+    ;
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getAggregatorCategoryRoutes() {
+    return array(
+      array('aggregator.category_view'),
+      array('aggregator.categorize_category_form'),
+      array('aggregator.category_edit'),
+    );
+  }
+
+  //
+  /**
+   * Check category aggregator tasks.
+   *
+   * @dataProvider getAggregatorSourceRoutes
+   */
+  public function testAggregatorSourceLocalTasks($route) {
+    $this->assertLocalTasks($route, array(
+      0 => array('aggregator.feed_view', 'aggregator.categorize_feed_form', 'aggregator.feed_configure'),
+    ));
+    ;
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getAggregatorSourceRoutes() {
+    return array(
+      array('aggregator.feed_view'),
+      array('aggregator.categorize_feed_form'),
+      array('aggregator.feed_configure'),
+    );
+  }
+}
diff --git a/core/modules/block/block.local_tasks.yml b/core/modules/block/block.local_tasks.yml
new file mode 100644
index 0000000..2a9b2ce
--- /dev/null
+++ b/core/modules/block/block.local_tasks.yml
@@ -0,0 +1,16 @@
+block.admin_edit:
+  route_name: block.admin_edit
+  title: 'Configure block'
+  tab_root_id: block.admin_edit
+
+# Per theme block layout pages.
+block.admin_display:
+  route_name: block.admin_display
+  title: 'Block Layout'
+  tab_root_id: block.admin_display
+block.admin_display_theme:
+  route_name: block.admin_display_theme
+  title: 'Block Layout'
+  tab_root_id: block.admin_display
+  tab_parent_id: block.admin_display
+  derivative: 'Drupal\block\Plugin\Derivative\ThemeLocalTask'
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index f1112d6..09d645e 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -104,10 +104,6 @@ function block_menu() {
     'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
     'route_name' => 'block.admin_display',
   );
-  $items['admin/structure/block/list'] = array(
-    'title' => 'Block layout',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
   $items['admin/structure/block/manage/%block'] = array(
     'title' => 'Configure block',
     'route_name' => 'block.admin_edit',
@@ -115,7 +111,7 @@ function block_menu() {
   $items['admin/structure/block/manage/%block/configure'] = array(
     'title' => 'Configure block',
     'type' => MENU_DEFAULT_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    'context' => MENU_CONTEXT_INLINE,
   );
   $items['admin/structure/block/add/%/%'] = array(
     'title' => 'Place block',
@@ -125,15 +121,9 @@ function block_menu() {
   // Block administration is tied to the theme and plugin definition so
   // that the plugin can appropriately attach to this URL structure.
   // @todo D8: Use dynamic % arguments instead of static, hard-coded theme names
-  //   and plugin IDs to decouple the routes from these dependencies and allow
-  //   hook_menu_local_tasks() to check for the untranslated tab_parent path.
+  //   and plugin IDs to decouple the routes from these dependencies.
   // @see http://drupal.org/node/1067408
   foreach (list_themes() as $key => $theme) {
-    $items["admin/structure/block/list/$key"] = array(
-      'title' => check_plain($theme->info['name']),
-      'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
-      'route_name' => "block.admin_display_$key",
-    );
     $items["admin/structure/block/demo/$key"] = array(
       'title' => check_plain($theme->info['name']),
       'route_name' => 'block.admin_demo',
diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml
index 3d24f81..ee0e4c9 100644
--- a/core/modules/block/block.routing.yml
+++ b/core/modules/block/block.routing.yml
@@ -30,6 +30,16 @@ block.admin_display:
   requirements:
     _permission: 'administer blocks'
 
+block.admin_display_theme:
+  path: 'admin/structure/block/list/{theme}'
+  defaults:
+    _controller: '\Drupal\block\Controller\BlockListController::listing'
+  options:
+    _access_mode: 'ALL'
+  requirements:
+    _access_theme: 'TRUE'
+    _permission: 'administer blocks'
+
 block.admin_add:
   path: '/admin/structure/block/add/{plugin_id}/{theme}'
   defaults:
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index c6704bc..b6bf1f4 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -9,7 +9,3 @@ services:
     factory_method: get
     factory_service: cache_factory
     arguments: [block]
-  block.route_subscriber:
-    class: Drupal\block\Routing\RouteSubscriber
-    tags:
-      - { name: event_subscriber}
diff --git a/core/modules/block/custom_block/custom_block.local_actions.yml b/core/modules/block/custom_block/custom_block.local_actions.yml
index 531668e..0b2e8ea 100644
--- a/core/modules/block/custom_block/custom_block.local_actions.yml
+++ b/core/modules/block/custom_block/custom_block.local_actions.yml
@@ -9,3 +9,5 @@ custom_block_add_action:
   title: 'Add custom block'
   appears_on:
     - block.admin_display
+    - block.admin_display_theme
+  class: \Drupal\custom_block\Plugin\Menu\LocalAction\CustomBlockAddLocalAction
diff --git a/core/modules/block/custom_block/custom_block.local_tasks.yml b/core/modules/block/custom_block/custom_block.local_tasks.yml
new file mode 100644
index 0000000..f2c341a
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.local_tasks.yml
@@ -0,0 +1,25 @@
+custom_block.list:
+  title: 'Custom block library'
+  route_name: custom_block.list
+  tab_root_id: block.admin_display
+custom_block.list_sub:
+  title: Blocks
+  route_name: custom_block.list
+  tab_root_id: block.admin_display
+  tab_parent_id: custom_block.list
+custom_block.type_list:
+  title: Types
+  route_name: custom_block.type_list
+  tab_root_id: block.admin_display
+  tab_parent_id: custom_block.list
+
+custom_block.edit:
+  title: Edit
+  route_name: custom_block.edit
+  tab_root_id: custom_block.edit
+  weight: 0
+custom_block.delete:
+  title: Delete
+  route_name: custom_block.delete
+  tab_root_id: custom_block.edit
+  weight: 1
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index 8e81778..1ac53b5 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -44,23 +44,6 @@ function custom_block_menu_local_tasks(&$data, $route_name) {
       );
     }
   }
-
-  $routes = array_map(function ($theme) {
-    return "block.admin_display_$theme";
-  }, array_keys(list_themes()));
-  if (in_array($route_name, $routes)) {
-    // @todo Move to a LocalAction plugin when https://drupal.org/node/2045267
-    //   allows local actions to work with query strings.
-    $item = menu_get_item('block/add');
-    if ($item['access']) {
-      // Add a destination parameter.
-      $item['localized_options']['query']['theme'] = \Drupal::request()->attributes->get('theme');
-      $data['actions']['block/add'] = array(
-        '#theme' => 'menu_local_action',
-        '#link' => $item,
-      );
-    }
-  }
 }
 
 /**
@@ -71,16 +54,6 @@ function custom_block_menu() {
     'title' => 'Custom block library',
     'description' => 'Manage custom blocks.',
     'route_name' => 'custom_block.list',
-    'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
-  );
-  $items['admin/structure/block/custom-blocks/list'] = array(
-    'title' => 'Blocks',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/structure/block/custom-blocks/types'] = array(
-    'title' => 'Types',
-    'route_name' => 'custom_block.type_list',
-    'type' => MENU_LOCAL_TASK,
   );
   $items['admin/structure/block/custom-blocks/types/add'] = array(
     'route_name' => 'custom_block.type_add',
@@ -115,14 +88,13 @@ function custom_block_menu() {
   $items['block/%custom_block/edit'] = array(
     'title' => 'Edit',
     'weight' => 0,
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    'type' => MENU_DEFAULT_LOCAL_TASK, // Not a local task. Breadcrumb management.
+    'context' => MENU_CONTEXT_INLINE,
   );
   $items['block/%custom_block/delete'] = array(
     'title' => 'Delete',
     'weight' => 1,
-    'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_INLINE,
+    'type' => MENU_DEFAULT_LOCAL_TASK, // Not a local task. Breadcrumb management.
     'route_name' => 'custom_block.delete',
   );
   return $items;
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
index e37328d..12f2b72 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
@@ -8,6 +8,7 @@
 namespace Drupal\custom_block\Plugin\Derivative;
 
 use Drupal\Component\Plugin\Derivative\DerivativeBase;
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
 
 /**
  * Retrieves block plugin definitions for all custom blocks.
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
new file mode 100644
index 0000000..aec47c8
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\custom_block\Plugin\Menu\LocalAction\CustomBlockAddLocalAction.
+ */
+
+namespace Drupal\custom_block\Plugin\Menu\LocalAction;
+
+use Drupal\Core\Menu\LocalActionDefault;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Modifies the 'Add custom block' local action.
+ */
+class CustomBlockAddLocalAction extends LocalActionDefault {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOptions(Request $request) {
+    $options = parent::getOptions($request);
+    // If the route specifies a theme, append it to the query string.
+    if ($request->attributes->has('theme_name')) {
+      $options['query']['theme'] = $request->attributes->get('theme_name');
+    }
+    return $options;
+  }
+
+}
diff --git a/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php b/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php
new file mode 100644
index 0000000..58a8ac0
--- /dev/null
+++ b/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\custom_block\Tests\Menu\CustomBlockLocalTasksTest
+ */
+
+namespace Drupal\custom_block\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of custom_block local tasks.
+ *
+ * @group Drupal
+ * @group Block
+ */
+class CustomBlockLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Custom Block local tasks test',
+      'description' => 'Test custom_block local tasks.',
+      'group' => 'Block',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array(
+      'block' => 'core/modules/block/block.info',
+      'custom_block' => 'core/modules/block/custom_block/custom_block.info',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Check custom_block listing local tasks
+   *
+   * @dataProvider getCustomBlockListingRoutes
+   */
+  public function testCustomBlockListLocalTasks($route) {
+    //
+    $this->assertLocalTasks($route, array(
+      0 => array(
+        'block.admin_display',
+        'custom_block.list',
+      ),
+      1 => array(
+        'custom_block.list_sub',
+        'custom_block.type_list',
+      )
+    ));
+  }
+
+  /**
+   * Provide a list of routes to test.C
+   */
+  public function getCustomBlockListingRoutes() {
+    return array(
+      array('custom_block.list', 'custom_block.type_list'),
+    );
+  }
+}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php b/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php
new file mode 100644
index 0000000..ba897e4
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Plugin\Derivative\ThemeLocalTask.
+ */
+
+namespace Drupal\block\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DerivativeBase;
+
+/**
+ * Provides dynamic tabs based on active themes.
+ */
+class ThemeLocalTask extends DerivativeBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    $default_theme = \Drupal::config('system.theme')->get('default');
+
+    foreach (list_themes() as $theme_name => $theme) {
+      if ($theme->status) {
+        $this->derivatives[$theme_name] = $base_plugin_definition;
+        $this->derivatives[$theme_name]['title'] = $theme->info['name'];
+        $this->derivatives[$theme_name]['route_parameters'] = array('theme_name' => $theme_name);
+      }
+      // Default task!
+      if ($default_theme == $theme_name) {
+        $this->derivatives[$theme_name]['route_name'] = 'block.admin_display';
+        // Emulate default logic because without the base plugin id we can't set the
+        // change the tab_root_id.
+        $this->derivatives[$theme_name]['weight'] = -10;
+
+        unset($this->derivatives[$theme_name]['route_parameters']);
+      }
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php b/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php
deleted file mode 100644
index f60e51a..0000000
--- a/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\block\Routing\RouteSubscriber.
- */
-
-namespace Drupal\block\Routing;
-
-use Drupal\Core\Routing\RouteBuildEvent;
-use Drupal\Core\Routing\RoutingEvents;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Listens to the dynamic route events.
- */
-class RouteSubscriber implements EventSubscriberInterface {
-
-  /**
-   * Implements EventSubscriberInterface::getSubscribedEvents().
-   */
-  public static function getSubscribedEvents() {
-    $events[RoutingEvents::DYNAMIC] = 'routes';
-    return $events;
-  }
-
-  /**
-   * Generate dynamic routes for various block pages.
-   *
-   * @param \Drupal\Core\Routing\RouteBuildEvent $event
-   *   The route building event.
-   *
-   * @return \Symfony\Component\Routing\RouteCollection
-   *   The route collection that contains the new dynamic route.
-   */
-  public function routes(RouteBuildEvent $event) {
-    $collection = $event->getRouteCollection();
-    foreach (list_themes(TRUE) as $key => $theme) {
-      // The block entity listing page.
-      $route = new Route(
-        "admin/structure/block/list/$key",
-        array(
-          '_controller' => '\Drupal\block\Controller\BlockListController::listing',
-          'theme' => $key,
-        ),
-        array(
-          '_access_theme' => 'TRUE',
-          '_permission' => 'administer blocks',
-        ),
-        array(
-          '_access_mode' => 'ALL',
-        )
-      );
-      $collection->add("block.admin_display_$key", $route);
-    }
-  }
-
-}
diff --git a/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php b/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php
new file mode 100644
index 0000000..5ac19bf
--- /dev/null
+++ b/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\Menu\BlockLocalTasksTest
+ */
+
+namespace Drupal\block\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of block local tasks.
+ *
+ * @group Drupal
+ * @group Block
+ */
+class BlockLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Block local tasks test',
+      'description' => 'Test block local tasks.',
+      'group' => 'Block',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array('block' => 'core/modules/block/block.info');
+    parent::setUp();
+  }
+
+  /**
+   * Test local task existence.
+   */
+  public function testBlockAdminLocalTasks() {
+    $this->markTestIncomplete(
+      'This test has not been implemented yet. list_theme() and Drupal::config() calls fail.'
+    );
+    //$this->assertLocalTasks('block.admin_edit', array(array('block.admin_edit')));
+  }
+
+  /**
+   * Check block listing local tasks
+   *
+   * @dataProvider getBlockListingRoutes
+   */
+  public function testBlockListLocalTasks($route) {
+    $this->markTestIncomplete(
+      'This test has not been implemented yet. list_theme() and Drupal::config() calls fail.'
+    );
+    //
+//    $this->assertLocalTasks($route, array(
+//      0 => array('aggregator.category_view', 'aggregator.categorize_feed_form', 'aggregator.feed_configure'),
+//    ));
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getBlockListingRoutes() {
+    return array(
+      array('placeholder'),
+      // theme_list()
+    );
+  }
+}
diff --git a/core/modules/book/book.local_tasks.yml b/core/modules/book/book.local_tasks.yml
new file mode 100644
index 0000000..f0f8464
--- /dev/null
+++ b/core/modules/book/book.local_tasks.yml
@@ -0,0 +1,15 @@
+book.admin:
+  route_name: book.admin
+  title: 'List'
+  tab_root_id: book.admin
+book.settings:
+  route_name: book.settings
+  title: 'Settings'
+  tab_root_id: book.admin
+  weight: 100
+
+book.outline:
+  route_name: book.outline
+  tab_root_id: node.view
+  title: Outline
+  weight: 2
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index aef8a52..f7be7d5 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -171,28 +171,11 @@ function book_menu() {
     'description' => "Manage your site's book outlines.",
     'route_name' => 'book.admin',
   );
-  $items['admin/structure/book/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/structure/book/settings'] = array(
-    'title' => 'Settings',
-    'route_name' => 'book.settings',
-    'access arguments' => array('administer site configuration'),
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 100,
-  );
   $items['book'] = array(
     'title' => 'Books',
     'route_name' => 'book.render',
     'type' => MENU_SUGGESTED_ITEM,
   );
-  $items['node/%node/outline'] = array(
-    'title' => 'Outline',
-    'route_name' => 'book.outline',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 2,
-  );
   $items['node/%node/outline/remove'] = array(
     'title' => 'Remove from outline',
     'route_name' => 'book.remove',
diff --git a/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php b/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php
new file mode 100644
index 0000000..e8aa150
--- /dev/null
+++ b/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\book\Tests\Menu\BookLocalTasksTest
+ */
+
+namespace Drupal\book\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of book local tasks.
+ *
+ * @group Drupal
+ * @group Book
+ */
+class BookLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Book local tasks test',
+      'description' => 'Test existence of book local tasks.',
+      'group' => 'Book',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array(
+      'book' => 'core/modules/book/book.info',
+      'node' => 'core/modules/node/node.info',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Test local task existence.
+   *
+   * @dataProvider getBookAdminRoutes
+   */
+  public function testBookAdminLocalTasks($route) {
+
+    $this->assertLocalTasks($route, array(
+      0 => array('book.admin', 'book.settings'),
+    ));
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getBookAdminRoutes() {
+    return array(
+      array('book.admin'),
+      array('book.settings'),
+    );
+  }
+
+  /**
+   * Test local task existence.
+   *
+   * @dataProvider getBookNodeRoutes
+   */
+  public function testBookNodeLocalTasks($route) {
+    $this->assertLocalTasks($route, array(
+      0 => array('book.outline', 'node.view', 'node.page_edit', 'node.delete_confirm', 'node.revision_overview',),
+    ));
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getBookNodeRoutes() {
+    return array(
+      array('node.view'),
+      array('book.outline'),
+    );
+  }
+}
diff --git a/core/modules/comment/comment.local_tasks.yml b/core/modules/comment/comment.local_tasks.yml
index 1c0c901..353a831 100644
--- a/core/modules/comment/comment.local_tasks.yml
+++ b/core/modules/comment/comment.local_tasks.yml
@@ -1,15 +1,15 @@
-comment.permalink_tab:
-  route_name: comment_permalink
+comment.permalink:
+  route_name: comment.permalink
   title: 'View comment'
-  tab_root_id: comment.permalink_tab
-comment.edit_page_tab:
-  route_name: comment_edit_page
+  tab_root_id: comment.permalink
+comment.edit_page:
+  route_name: comment.edit_page
   title: 'Edit'
-  tab_root_id: comment.permalink_tab
+  tab_root_id: comment.permalink
   weight: 0
-comment.confirm_delete_tab:
-  route_name: comment_confirm_delete
+comment.confirm_delete:
+  route_name: comment.confirm_delete
   title: 'Delete'
-  tab_root_id: comment.permalink_tab
+  tab_root_id: comment.permalink
   weight: 10
 
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 2034cda..6733ba5 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -227,28 +227,28 @@ function comment_menu() {
     'title' => 'Comment permalink',
     'route_name' => 'comment.permalink',
   );
-  $items['comment/%comment/view'] = array(
-    'title' => 'View comment',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  // Every other comment path uses %, but this one loads the comment directly,
-  // so we don't end up loading it twice (in the page and access callback).
-  $items['comment/%comment/edit'] = array(
-    'title' => 'Edit',
-    'type' => MENU_LOCAL_TASK,
-    'route_name' => 'comment.edit_page',
-  );
+//  $items['comment/%comment/view'] = array(
+//    'title' => 'View comment',
+//    'type' => MENU_DEFAULT_LOCAL_TASK,
+//  );
+//  // Every other comment path uses %, but this one loads the comment directly,
+//  // so we don't end up loading it twice (in the page and access callback).
+//  $items['comment/%comment/edit'] = array(
+//    'title' => 'Edit',
+//    'type' => MENU_LOCAL_TASK,
+//    'route_name' => 'comment.edit_page',
+//  );
   $items['comment/%comment/approve'] = array(
     'title' => 'Approve',
     'weight' => 10,
     'route_name' => 'comment.approve',
   );
-  $items['comment/%comment/delete'] = array(
-    'title' => 'Delete',
-    'type' => MENU_LOCAL_TASK,
-    'route_name' => 'comment.confirm_delete',
-    'weight' => 20,
-  );
+//  $items['comment/%comment/delete'] = array(
+//    'title' => 'Delete',
+//    'type' => MENU_LOCAL_TASK,
+//    'route_name' => 'comment.confirm_delete',
+//    'weight' => 20,
+//  );
 
   return $items;
 }
diff --git a/core/modules/config/config.local_tasks.yml b/core/modules/config/config.local_tasks.yml
new file mode 100644
index 0000000..c2b6916
--- /dev/null
+++ b/core/modules/config/config.local_tasks.yml
@@ -0,0 +1,22 @@
+config.sync:
+  route_name: config.sync
+  tab_root_id: config.sync
+  title: 'Synchronize'
+  weight: 0
+config.export:
+  route_name: config.export
+  tab_root_id: config.sync
+  title: Export
+  weight: 1
+config.import:
+  route_name: config.import
+  title: Import
+  tab_root_id: config.sync
+  weight: 2
+# todo I'm not sure why there are two imports. is there history here?
+config.sync_import:
+  route_name: config.sync
+  tab_root_id: config.sync
+  tab_parent_id: config.sync
+  title: 'Import'
+  weight: 0
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index 5e93c02..6d73294 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -64,37 +64,29 @@ function config_menu() {
   $items['admin/config/development/configuration'] = array(
     'title' => 'Configuration management',
     'description' => 'Import, export, or synchronize your site configuration.',
-    'route_name' => 'config_management',
+    'route_name' => 'config.sync',
   );
+  #this page doesn't really exist. It was an old task that collapsed up.
   $items['admin/config/development/configuration/sync'] = array(
     'title' => 'Synchronize',
     'description' => 'Synchronize configuration changes.',
     'route_name' => 'config.sync',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => 0,
   );
   $items['admin/config/development/configuration/export'] = array(
     'title' => 'Export',
     'description' => 'Export your site configuration',
     'route_name' => 'config.export',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 1,
   );
   $items['admin/config/development/configuration/import'] = array(
     'title' => 'Import',
     'description' => 'Import configuration for your site',
     'route_name' => 'config.import',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 2,
   );
   $items['admin/config/development/configuration/sync/diff/%'] = array(
     'title' => 'Configuration file diff',
     'description' => 'Diff between active and staged configuration.',
     'route_name' => 'config.diff',
   );
-  $items['admin/config/development/configuration/sync/import'] = array(
-    'title' => 'Import',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
+
   return $items;
 }
diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml
index 3eaeb34..c3a6850 100644
--- a/core/modules/config/config.routing.yml
+++ b/core/modules/config/config.routing.yml
@@ -1,14 +1,14 @@
-config.diff:
-  path: '/admin/config/development/configuration/sync/diff/{config_file}'
+config.sync:
+  path: '/admin/config/development/configuration'
   defaults:
-    _content: '\Drupal\config\Controller\ConfigController::diff'
+    _form: '\Drupal\config\Form\ConfigSync'
   requirements:
     _permission: 'synchronize configuration'
 
-config_management:
-  path: '/admin/config/development/configuration'
+config.diff:
+  path: '/admin/config/development/configuration/sync/diff/{config_file}'
   defaults:
-    _form: '\Drupal\config\Form\ConfigSync'
+    _content: '\Drupal\config\Controller\ConfigController::diff'
   requirements:
     _permission: 'synchronize configuration'
 
@@ -32,10 +32,3 @@ config.import:
     _form: '\Drupal\config\Form\ConfigImportForm'
   requirements:
     _permission: 'import configuration'
-
-config.sync:
-  path: '/admin/config/development/configuration/sync'
-  defaults:
-    _form: '\Drupal\config\Form\ConfigSync'
-  requirements:
-    _permission: 'synchronize configuration'
diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
index 59cb82b..1c13a01 100644
--- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
+++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
@@ -123,7 +123,7 @@ public function diff($config_file) {
         ),
       ),
       '#title' => "Back to 'Synchronize configuration' page.",
-      '#href' => 'admin/config/development/configuration/sync',
+      '#href' => 'admin/config/development/configuration',
     );
 
     return $build;
diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
index a18a971..e25a392 100644
--- a/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
+++ b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
@@ -96,7 +96,7 @@ public function submitForm(array &$form, array &$form_state) {
         }
         $archiver->extractList($files, config_get_config_directory(CONFIG_STAGING_DIRECTORY));
         drupal_set_message($this->t('Your configuration files were successfully uploaded, ready for import.'));
-        $form_state['redirect'] = 'admin/config/development/configuration/sync';
+        $form_state['redirect'] = 'admin/config/development/configuration';
       }
       catch (\Exception $e) {
         form_set_error('import_tarball', $this->t('Could not extract the contents of the tar file. The error message is <em>@message</em>', array('@message' => $e->getMessage())));
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
index 58fc2d5..0148011 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
@@ -41,7 +41,7 @@ function testImport() {
     $storage = $this->container->get('config.storage');
     $staging = $this->container->get('config.storage.staging');
 
-    $this->drupalGet('admin/config/development/configuration/sync');
+    $this->drupalGet('admin/config/development/configuration');
     $this->assertText('There are no configuration changes.');
     $this->assertNoFieldById('edit-submit', t('Import all'));
 
@@ -65,7 +65,7 @@ function testImport() {
     $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
 
     // Verify that both appear as ready to import.
-    $this->drupalGet('admin/config/development/configuration/sync');
+    $this->drupalGet('admin/config/development/configuration');
     $this->assertText($name);
     $this->assertText($dynamic_name);
     $this->assertFieldById('edit-submit', t('Import all'));
@@ -98,7 +98,7 @@ function testImportLock() {
     $this->prepareSiteNameUpdate($new_site_name);
 
     // Verify that there are configuration differences to import.
-    $this->drupalGet('admin/config/development/configuration/sync');
+    $this->drupalGet('admin/config/development/configuration');
     $this->assertNoText(t('There are no configuration changes.'));
 
     // Acquire a fake-lock on the import mechanism.
diff --git a/core/modules/field_ui/field_ui.local_tasks.yml b/core/modules/field_ui/field_ui.local_tasks.yml
new file mode 100644
index 0000000..e690491
--- /dev/null
+++ b/core/modules/field_ui/field_ui.local_tasks.yml
@@ -0,0 +1,4 @@
+field_ui.list:
+  title: Entities
+  route_name: field_ui.list
+  tab_root_id: field_ui.list
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 0d81232..dc0d38f 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -60,10 +60,6 @@ function field_ui_menu() {
     'route_name' => 'field_ui.list',
     'type' => MENU_NORMAL_ITEM,
   );
-  $items['admin/reports/fields/list'] = array(
-    'title' => 'Entities',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
 
   // Create tabs for all possible bundles.
   foreach (entity_get_info() as $entity_type => $entity_info) {
diff --git a/core/modules/forum/forum.local_tasks.yml b/core/modules/forum/forum.local_tasks.yml
new file mode 100644
index 0000000..4cd9dcb
--- /dev/null
+++ b/core/modules/forum/forum.local_tasks.yml
@@ -0,0 +1,9 @@
+forum.overview:
+  route_name: forum.overview
+  tab_root_id: forum.overview
+  title: List
+forum.settings:
+  route_name: forum.settings
+  tab_root_id: forum.overview
+  title: Settings
+  weight: 100
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 4593c72..36f1239 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -119,17 +119,6 @@ function forum_menu() {
     'description' => 'Control forum hierarchy settings.',
     'route_name' => 'forum.overview',
   );
-  $items['admin/structure/forum/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/structure/forum/settings'] = array(
-    'title' => 'Settings',
-    'weight' => 100,
-    'type' => MENU_LOCAL_TASK,
-    'parent' => 'admin/structure/forum',
-    'route_name' => 'forum.settings',
-  );
   $items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
     'title' => 'Edit container',
     'route_name' => 'forum.edit_container',
diff --git a/core/modules/locale/locale.local_tasks.yml b/core/modules/locale/locale.local_tasks.yml
new file mode 100644
index 0000000..ade24ed
--- /dev/null
+++ b/core/modules/locale/locale.local_tasks.yml
@@ -0,0 +1,22 @@
+locale.translate_page:
+  route_name: locale.translate_page
+  tab_root_id: locale.translate_page
+  title: Translate
+
+locale.translate_import:
+  route_name: locale.translate_import
+  tab_root_id: locale.translate_page
+  title: Import
+  weight: 20
+
+locale.translate_export:
+  route_name: locale.translate_export
+  tab_root_id: locale.translate_page
+  title: Export
+  weight: 30
+
+locale.settings:
+  route_name: locale.settings
+  tab_root_id: locale.translate_page
+  title: Settings
+  weight: 100
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 5817e1b..d6efb0a 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -176,28 +176,7 @@ function locale_menu() {
     'route_name' => 'locale.translate_page',
     'weight' => -5,
   );
-  $items['admin/config/regional/translate/translate'] = array(
-    'title' => 'Translate',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/regional/translate/import'] = array(
-    'title' => 'Import',
-    'route_name' => 'locale.translate_import',
-    'weight' => 20,
-    'type' => MENU_LOCAL_TASK,
-  );
-  $items['admin/config/regional/translate/export'] = array(
-    'title' => 'Export',
-    'route_name' => 'locale.translate_export',
-    'weight' => 30,
-    'type' => MENU_LOCAL_TASK,
-  );
-  $items['admin/config/regional/translate/settings'] = array(
-    'title' => 'Settings',
-    'route_name' => 'locale.settings',
-    'weight' => 100,
-    'type' => MENU_LOCAL_TASK,
-  );
+
   $items['admin/reports/translations'] = array(
     'title' => 'Available translation updates',
     'route_name' => 'locale.translate_status',
diff --git a/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php b/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php
new file mode 100644
index 0000000..187df06
--- /dev/null
+++ b/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\locale\Tests\Menu\LocaleLocalTasksTest
+ */
+
+namespace Drupal\locale\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of locale local tasks.
+ *
+ * @group Drupal
+ * @group Locale
+ */
+class LocaleLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Locale local tasks test',
+      'description' => 'Test locale local tasks.',
+      'group' => 'Locale',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array(
+      'locale' => 'core/modules/locale/locale.info',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Check locale listing local tasks
+   *
+   * @dataProvider getLocalePageRoutes
+   */
+  public function testLocalePageLocalTasks($route) {
+    $tasks = array(
+      0 => array('locale.translate_page', 'locale.translate_import', 'locale.translate_export','locale.settings'),
+    );
+    $this->assertLocalTasks($route, $tasks);
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getLocalePageRoutes() {
+    return array(
+      array('locale.translate_page'),
+      array('locale.translate_import'),
+      array('locale.translate_export'),
+      array('locale.settings'),
+    );
+  }
+}
diff --git a/core/modules/node/node.local_tasks.yml b/core/modules/node/node.local_tasks.yml
new file mode 100644
index 0000000..24d9ef2
--- /dev/null
+++ b/core/modules/node/node.local_tasks.yml
@@ -0,0 +1,18 @@
+node.view:
+  route_name: node.view
+  tab_root_id: node.view
+  title: 'View'
+node.page_edit:
+  route_name: node.page_edit
+  tab_root_id: node.view
+  title: Edit
+node.delete_confirm:
+  route_name: node.delete_confirm
+  tab_root_id: node.view
+  title: Delete
+  weight: 10
+node.revision_overview:
+  route_name: node.revision_overview
+  tab_root_id: node.view
+  title: 'Revisions'
+  weight: 20
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 772481b9..8a65e81 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -999,7 +999,7 @@ function node_menu() {
   );
   $items['admin/structure/types/manage/%node_type/edit'] = array(
     'title' => 'Edit',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'type' => MENU_DEFAULT_LOCAL_TASK, // Entity base
   );
   $items['node/add'] = array(
     'title' => 'Add content',
@@ -1019,15 +1019,11 @@ function node_menu() {
     // overridden by a menu link.
     'route_name' => 'node.view',
   );
-  $items['node/%node/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
   $items['node/%node/edit'] = array(
     'title' => 'Edit',
     'route_name' => 'node.page_edit',
     'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    'context' => MENU_CONTEXT_INLINE,
   );
   $items['node/%node/delete'] = array(
     'title' => 'Delete',
@@ -1036,12 +1032,6 @@ function node_menu() {
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_INLINE,
   );
-  $items['node/%node/revisions'] = array(
-    'title' => 'Revisions',
-    'route_name' => 'node.revision_overview',
-    'weight' => 20,
-    'type' => MENU_LOCAL_TASK,
-  );
   $items['node/%node/revisions/%node_revision/view'] = array(
     'title' => 'Revisions',
     'route_name' => 'node.revision_show',
diff --git a/core/modules/shortcut/shortcut.local_tasks.yml b/core/modules/shortcut/shortcut.local_tasks.yml
new file mode 100644
index 0000000..edfeaeb
--- /dev/null
+++ b/core/modules/shortcut/shortcut.local_tasks.yml
@@ -0,0 +1,4 @@
+shortcut.overview:
+  route_name: shortcut.overview
+  tab_root_id: user.view
+  title: 'Shortcuts'
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 175206d..639419a 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -119,11 +119,6 @@ function shortcut_menu() {
     'title' => 'Delete shortcut',
     'route_name' => 'shortcut.link_delete',
   );
-  $items['user/%user/shortcuts'] = array(
-    'title' => 'Shortcuts',
-    'route_name' => 'shortcut.overview',
-    'type' => MENU_LOCAL_TASK,
-  );
 
   return $items;
 }
diff --git a/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php b/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php
new file mode 100644
index 0000000..4e52d49
--- /dev/null
+++ b/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\shortcut\Tests\Menu\ShortcutLocalTasksTest
+ */
+
+namespace Drupal\shortcut\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of shortcut local tasks.
+ *
+ * @group Drupal
+ * @group Shortcut
+ */
+class ShortcutLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Shortcut local tasks test',
+      'description' => 'Test shortcut local tasks.',
+      'group' => 'Shortcut',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array(
+      'shortcut' => 'core/modules/shortcut/shortcut.info',
+      'user' => 'core/modules/user/user.info',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Check shortcut listing local tasks
+   *
+   * @dataProvider getShortcutPageRoutes
+   */
+  public function testShortcutPageLocalTasks($route) {
+    $tasks = array(
+      0 => array('shortcut.overview', 'user.view', 'user.edit',),
+    );
+    $this->assertLocalTasks($route, $tasks);
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getShortcutPageRoutes() {
+    return array(
+      array('user.view'),
+      array('user.edit'),
+      array('shortcut.overview'),
+    );
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php b/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php
new file mode 100644
index 0000000..992fc03
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Plugin\Derivative\ThemeLocalTask.
+ */
+
+namespace Drupal\system\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DerivativeBase;
+
+/**
+ * Provides dynamic tabs based on active themes.
+ */
+class ThemeLocalTask extends DerivativeBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    foreach (list_themes() as $theme_name => $theme) {
+      if ($theme->status) {
+        $this->derivatives[$theme_name] = $base_plugin_definition;
+        $this->derivatives[$theme_name]['title'] = $theme->info['name'];
+        $this->derivatives[$theme_name]['route_parameters'] = array('theme_name' => $theme_name);
+      }
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php b/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
deleted file mode 100644
index 600e6af..0000000
--- a/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\EventSubscriber\RouteSubscriber.
- */
-
-namespace Drupal\system\Routing;
-
-use Drupal\Core\Routing\RouteBuildEvent;
-use Drupal\Core\Routing\RoutingEvents;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\Routing\Route;
-
-/**
- * Event subscriber for routes.
- */
-class RouteSubscriber implements EventSubscriberInterface {
-
-  /**
-   * Implements EventSubscriberInterface::getSubscribedEvents().
-   */
-  static function getSubscribedEvents() {
-    $events[RoutingEvents::DYNAMIC] = 'createSystemThemeRoutes';
-    return $events;
-  }
-
-  /**
-   * Adds dynamic system theme routes.
-   *
-   * @param \Drupal\Core\Routing\RouteBuildEvent $event
-   *   The route building event.
-   */
-  public function createSystemThemeRoutes(RouteBuildEvent $event) {
-    $collection = $event->getRouteCollection();
-    foreach (list_themes() as $theme) {
-      if (!empty($theme->status)) {
-        $route = new Route('admin/appearance/settings/' . $theme->name, array(
-          '_form' => '\Drupal\system\Form\ThemeSettingsForm', 'theme_name' => $theme->name), array(
-          '_permission' => 'administer themes',
-        ));
-        $collection->add('system.theme_settings_' . $theme->name, $route);
-      }
-    }
-  }
-
-}
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index f1a428f..6d7bc01 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -213,7 +213,9 @@ function system_theme_default() {
       // implementations, and doing the variable_set() before the theme_enable()
       // could result in a race condition where the theme is default but not
       // enabled.
+      \Drupal::service('router.builder')->rebuild();
       menu_router_rebuild();
+      \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
 
       // 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.
diff --git a/core/modules/system/system.local_tasks.yml b/core/modules/system/system.local_tasks.yml
index 575e515..3fe3911 100644
--- a/core/modules/system/system.local_tasks.yml
+++ b/core/modules/system/system.local_tasks.yml
@@ -12,3 +12,53 @@ system.site_information_settings_tab:
   route_name: system.site_information_settings
   title: Settings
   tab_root_id: system.site_information_settings_tab
+
+system.themes_page:
+  route_name: system.themes_page
+  title: List
+  description: 'Select and configure your theme'
+  tab_root_id: system.themes_page
+
+system.theme_settings:
+  route_name: system.theme_settings
+  title: Settings
+  description: 'Configure default and theme specific settings.'
+  tab_root_id: system.themes_page
+  weight: 100
+
+system.theme_settings_global:
+  route_name: system.theme_settings
+  title: 'Global settings'
+  tab_root_id: system.themes_page
+  tab_parent_id: system.theme_settings
+  description: 'Configure default and theme specific settings.'
+  weight: -100
+
+system.theme_settings_theme:
+  route_name: system.theme_settings_theme
+  title: 'Theme name'
+  tab_root_id: system.themes_page
+  tab_parent_id: system.theme_settings
+  derivative: Drupal\system\Plugin\Derivative\ThemeLocalTask
+
+system.modules_list:
+  route_name: system.modules_list
+  tab_root_id: system.modules_list
+  title: 'List'
+
+system.modules_uninstall:
+  route_name: system.modules_uninstall
+  tab_root_id: system.modules_list
+  title: 'Uninstall'
+  weight: 20
+
+system.admin:
+  route_name: system.admin
+  tab_root_id: system.admin
+  title: Tasks
+  weight: -20
+system.admin_index:
+  route_name: system.admin_index
+  tab_root_id: system.admin
+  title: Index
+  weight: -18
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 03f9042..5632cce 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -620,17 +620,6 @@ function system_menu() {
     'weight' => 9,
     'menu_name' => 'admin',
   );
-  $items['admin/tasks'] = array(
-    'title' => 'Tasks',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -20,
-  );
-  $items['admin/index'] = array(
-    'title' => 'Index',
-    'route_name' => 'system.admin_index',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => -18,
-  );
 
   // Menu items that are basically just menu blocks.
   $items['admin/structure'] = array(
@@ -648,34 +637,6 @@ function system_menu() {
     'position' => 'left',
     'weight' => -6,
   );
-  $items['admin/appearance/list'] = array(
-    'title' => 'List',
-    'description' => 'Select and configure your theme',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'file' => 'system.admin.inc',
-  );
-  $items['admin/appearance/settings'] = array(
-    'title' => 'Settings',
-    'description' => 'Configure default and theme specific settings.',
-    'route_name' => 'system.theme_settings',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 100,
-  );
-  // Theme configuration local tasks.
-  $items['admin/appearance/settings/global'] = array(
-    'title' => 'Global settings',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-
-  foreach (list_themes(TRUE) as $theme) {
-    if (!empty($theme->status)) {
-      $items['admin/appearance/settings/' . $theme->name] = array(
-        'title' => $theme->info['name'],
-        'route_name' => 'system.theme_settings_' . $theme->name,
-        'type' => MENU_LOCAL_TASK,
-      );
-    }
-  }
 
   // Modules.
   $items['admin/modules'] = array(
@@ -684,21 +645,11 @@ function system_menu() {
     'route_name' => 'system.modules_list',
     'weight' => -2,
   );
-  $items['admin/modules/list'] = array(
-    'title' => 'List',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
   $items['admin/modules/list/confirm'] = array(
     'title' => 'List',
     'route_name' => 'system.modules_list_confirm',
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
   );
-  $items['admin/modules/uninstall'] = array(
-    'title' => 'Uninstall',
-    'route_name' => 'system.modules_uninstall',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 20,
-  );
   $items['admin/modules/uninstall/confirm'] = array(
     'title' => 'Uninstall',
     'route_name' => 'system.modules_uninstall_confirm',
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index b1bd784..0ca5476 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -324,6 +324,13 @@ system.theme_settings:
   requirements:
     _permission: 'administer themes'
 
+system.theme_settings_theme:
+  path: '/admin/appearance/settings/{theme_name}'
+  defaults:
+    _form: '\Drupal\system\Form\ThemeSettingsForm'
+  requirements:
+    _permission: 'administer themes'
+
 '<front>':
   path: '/'
   requirements:
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 6a68e29..3371dad 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -19,7 +19,3 @@ services:
     class: Drupal\system\PathProcessor\PathProcessorFiles
     tags:
       - { name: path_processor_inbound, priority: 200 }
-  system.route_subscriber:
-    class: Drupal\system\Routing\RouteSubscriber
-    tags:
-      - { name: event_subscriber }
diff --git a/core/modules/update/update.local_tasks.yml b/core/modules/update/update.local_tasks.yml
new file mode 100644
index 0000000..cf1e3b6
--- /dev/null
+++ b/core/modules/update/update.local_tasks.yml
@@ -0,0 +1,29 @@
+update.status:
+  route_name: update.status
+  tab_root_id: system.admin_reports
+  title: List
+
+update.settings:
+  route_name: update.settings
+  tab_root_id: system.admin_reports
+  tab_parent_id: update.status
+  title: Settings
+  weight: 50
+
+update.report_install:
+  route_name: update.report_install
+  tab_root_id: system.admin_reports
+  title: Update
+  weight: 10
+
+update.module_install:
+  route_name: update.module_install
+  tab_root_id: system.modules_list
+  title: Update
+  weight: 10
+
+update.theme_install:
+  route_name: update.theme_install
+  tab_root_id: system.themes_page
+  title: Update
+  weight: 10
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 4258644..317e3e1 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -161,18 +161,6 @@ function update_menu() {
     'route_name' => 'update.status',
     'weight' => -50,
   );
-  $items['admin/reports/updates/list'] = array(
-    'title' => 'List',
-    'access arguments' => array('administer site configuration'),
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/reports/updates/settings'] = array(
-    'title' => 'Settings',
-    'route_name' => 'update.settings',
-    'access arguments' => array('administer site configuration'),
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 50,
-  );
 
   // We want action links for updating projects at a few different locations:
   // both the module and theme administration pages, and on the available
@@ -191,12 +179,6 @@ function update_menu() {
       'weight' => 25,
       'type' => MENU_LOCAL_ACTION,
     );
-    $items[$path . '/update'] = array(
-      'route_name' => "update.{$context}_update",
-      'weight' => 10,
-      'title' => 'Update',
-      'type' => MENU_LOCAL_TASK,
-    );
   }
   // Customize the titles of the action links depending on where they appear.
   // We use += array() to let the translation extractor find these menu titles.
diff --git a/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php b/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php
new file mode 100644
index 0000000..4f51de2
--- /dev/null
+++ b/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Menu\UserLocalTasksTest
+ */
+
+namespace Drupal\user\Tests\Menu;
+
+use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
+
+/**
+ * Tests existence of user local tasks.
+ *
+ * @group Drupal
+ * @group User
+ */
+class UserLocalTasksTest extends LocalTaskIntegrationTest {
+
+  /**
+   * SimpleTest info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'User local tasks test',
+      'description' => 'Test user local tasks.',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * @{inheritdoc}
+   */
+  public function setUp() {
+    $this->moduleList = array('user' => 'core/modules/user/user.info');
+    parent::setUp();
+  }
+
+//  /**
+//   * Test local task existence.
+//   *
+//   * @dataProvider getUserAdminRoutes
+//   */
+//  public function tesstUserAdminLocalTasks() {
+//  }
+//
+//  public function getUserAdminRoutes() {
+//    return array(
+//      array('user.page', 'user.register', 'user.pass'),
+//    );
+//  }
+//
+  /**
+   * Check user listing local tasks
+   *
+   * @dataProvider getUserLoginRoutes
+   */
+  public function testUserLoginLocalTasks($route, $subtask = array()) {
+    $tasks = array(
+      0 => array('user.page', 'user.register', 'user.pass',),
+    );
+    if ($subtask) $tasks[] = $subtask;
+    $this->assertLocalTasks($route, $tasks);
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getUserLoginRoutes() {
+    return array(
+      array('user.page', array('user.login',)),
+      array('user.login', array('user.login',)),
+      array('user.register'),
+      array('user.pass'),
+    );
+  }
+
+  /**
+   * Check user listing local tasks
+   *
+   * @dataProvider getUserPageRoutes
+   */
+  public function testUserPageLocalTasks($route, $subtask = array()) {
+    $tasks = array(
+      0 => array('user.view', 'user.edit',),
+    );
+    if ($subtask) $tasks[] = $subtask;
+    $this->assertLocalTasks($route, $tasks);
+  }
+
+  /**
+   * Provide a list of routes to test.
+   */
+  public function getUserPageRoutes() {
+    return array(
+      array('user.view'),
+      array('user.edit'),
+    );
+  }
+
+}
diff --git a/core/modules/user/user.local_tasks.yml b/core/modules/user/user.local_tasks.yml
index 0b40260..f09adfb 100644
--- a/core/modules/user/user.local_tasks.yml
+++ b/core/modules/user/user.local_tasks.yml
@@ -2,7 +2,41 @@ user.role_list_tab:
   route_name: user.role_list
   title: 'Roles'
   tab_root_id: user.role_list_tab
+
 user.account_settings_tab:
   route_name: user.account_settings
   title: 'Settings'
   tab_root_id: user.account_settings_tab
+
+user.page:
+  route_name: user.page
+  tab_root_id: user.page
+  title: 'Log in'
+  weight: -10
+
+user.register:
+  route_name: user.register
+  tab_root_id: user.page
+  title: 'Create new account'
+
+user.pass:
+  route_name: user.pass
+  tab_root_id: user.page
+  title: 'Request new password'
+
+# Other authentication methods may add pages below user/login/.
+user.login:
+  route_name: user.login
+  tab_root_id: user.page
+  tab_parent_id: user.page
+  title: 'Username and password'
+
+user.view:
+  route_name: user.view
+  tab_root_id: user.view
+  title: View
+
+user.edit:
+  route_name: user.edit
+  tab_root_id: user.view
+  title: Edit
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index aa2b2e8..51517b5 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -738,27 +738,6 @@ function user_menu() {
     'menu_name' => 'account',
   );
 
-  $items['user/login'] = array(
-    'title' => 'Log in',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  // Other authentication methods may add pages below user/login/.
-  $items['user/login/default'] = array(
-    'title' => 'Username and password',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-
-  $items['user/register'] = array(
-    'title' => 'Create new account',
-    'type' => MENU_LOCAL_TASK,
-    'route_name' => 'user.register',
-  );
-
-  $items['user/password'] = array(
-    'title' => 'Request new password',
-    'route_name' => 'user.pass',
-    'type' => MENU_LOCAL_TASK,
-  );
   // Since menu_get_ancestors() does not support multiple placeholders in a row,
   // this MENU_CALLBACK cannot be removed yet.
   $items['user/reset/%/%/%'] = array(
@@ -836,10 +815,6 @@ function user_menu() {
     'title arguments' => array(1),
     'route_name' => 'user.view',
   );
-  $items['user/%user/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
   $items['user/%user/cancel'] = array(
     'route_name' => 'user.cancel',
   );
@@ -847,11 +822,6 @@ function user_menu() {
     'title' => 'Confirm account cancellation',
     'route_name' => 'user.cancel_confirm',
   );
-  $items['user/%user/edit'] = array(
-    'title' => 'Edit',
-    'route_name' => 'user.edit',
-    'type' => MENU_LOCAL_TASK,
-  );
   return $items;
 }
 
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 169343b..25cfc3e 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -2,6 +2,7 @@ user.register:
   path: '/user/register'
   defaults:
     _entity_form: 'user.register'
+    _title: 'Create new account'
   requirements:
     _access_user_register: 'TRUE'
 
@@ -108,6 +109,7 @@ user.pass:
   path: '/user/password'
   defaults:
     _form: '\Drupal\user\Form\UserPasswordForm'
+    _title: 'Request new password'
   requirements:
     _access: 'TRUE'
 
@@ -131,6 +133,7 @@ user.login:
   path: '/user/login'
   defaults:
     _form: '\Drupal\user\Form\UserLoginForm'
+    _title: 'Log in'
   requirements:
     _access: 'TRUE'
 
diff --git a/core/modules/views_ui/views_ui.local_tasks.yml b/core/modules/views_ui/views_ui.local_tasks.yml
index 68fc7dc..6b1e9aa 100644
--- a/core/modules/views_ui/views_ui.local_tasks.yml
+++ b/core/modules/views_ui/views_ui.local_tasks.yml
@@ -1,22 +1,22 @@
-views_ui.settings_tab:
+views_ui.settings:
   route_name: views_ui.settings_basic
   title: Settings
-  tab_root_id: views_ui.list_tab
+  tab_root_id: views_ui.list
 
-views_ui.settings_basic_tab:
+views_ui.settings_basic:
   route_name: views_ui.settings_basic
   title: Basic
-  tab_root_id: views_ui.list_tab
-  tab_parent_id: views_ui.settings_tab
+  tab_root_id: views_ui.list
+  tab_parent_id: views_ui.settings
 
-views_ui.settings_advanced_tab:
+views_ui.settings_advanced:
   route_name: views_ui.settings_advanced
   title: Advanced
-  tab_root_id: views_ui.list_tab
-  tab_parent_id: views_ui.settings_tab
+  tab_root_id: views_ui.list
+  tab_parent_id: views_ui.settings
   weight: 10
 
-views_ui.list_tab:
+views_ui.list:
   route_name: views_ui.list
   title: List
-  tab_root_id: views_ui.list_tab
+  tab_root_id: views_ui.list
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 6da5339..b8a6bbb 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -47,11 +47,11 @@ function views_ui_menu() {
   $items['admin/structure/views/view/%/edit'] = array(
     'title' => 'Edit view',
     'type' => MENU_DEFAULT_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    'context' => MENU_CONTEXT_INLINE,
   );
+
   $items['admin/structure/views/view/%/preview/%'] = array(
     'route_name' => 'views_ui.preview',
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
   );
 
@@ -73,7 +73,6 @@ function views_ui_menu() {
     'title' => 'Used in views',
     'description' => 'Overview of fields used in all views.',
     'route_name' => 'views_ui.reports_fields',
-    'type' => MENU_LOCAL_TASK,
   );
 
   // A page in the Reports section to show usage of plugins in all views.
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
new file mode 100644
index 0000000..0399f4b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Menu\LocalTaskUnitTest.
+ */
+
+namespace Drupal\Tests\Core\Menu;
+
+use Drupal\Core\Extension\ModuleHandler;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
+use Drupal\Core\Plugin\Discovery\YamlDiscovery;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Base unit test for testing existence of local tasks.
+ *
+ * @todo help do access checking.
+ * @todo help with url building, title and other data checks.
+ */
+abstract class LocalTaskIntegrationTest extends UnitTestCase {
+
+  /**
+   * A list of modules used for yaml searching..
+   *
+   * @var array
+   */
+  protected $moduleList;
+
+  /**
+   * Setups the local task manager for the test.
+   */
+  protected function getLocalTaskManager($modules, $route_name, $route_params) {
+    $manager = $this
+      ->getMockBuilder('Drupal\Core\Menu\LocalTaskManager')
+      ->disableOriginalConstructor()
+      ->setMethods(NULL)
+      ->getMock();
+
+    $controllerResolver = $this->getMock('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface');
+    $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'controllerResolver');
+    $property->setAccessible(TRUE);
+    $property->setValue($manager, $controllerResolver);
+
+    // todo mock a request with a route.
+    $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+    $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'request');
+    $property->setAccessible(TRUE);
+    $property->setValue($manager, $request);
+
+    $accessManager = $this->getMockBuilder('Drupal\Core\Access\AccessManager')
+      ->disableOriginalConstructor()
+      ->getMock();    $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'accessManager');
+    $property->setAccessible(TRUE);
+    $property->setValue($manager, $accessManager);
+
+    $module_handler = new ModuleHandler($modules);
+    $pluginDiscovery = new YamlDiscovery('local_tasks', $module_handler->getModuleDirectories());
+    $pluginDiscovery = new ContainerDerivativeDiscoveryDecorator($pluginDiscovery);
+    $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'discovery');
+    $property->setAccessible(TRUE);
+    $property->setValue($manager, $pluginDiscovery);
+
+    $plugin_stub = $this->getMock('Drupal\Core\Menu\LocalTaskInterface');
+    $factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
+    $factory->expects($this->any())
+      ->method('createInstance')
+      ->will($this->returnValue($plugin_stub));
+    $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'factory');
+    $property->setAccessible(TRUE);
+    $property->setValue($manager, $factory);
+
+    $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $language_manager->expects($this->any())
+      ->method('getLanguage')
+      ->will($this->returnValue(new Language(array('id' => 'en'))));
+
+    $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+    $manager->setCacheBackend($cache_backend, $language_manager, 'local_task');
+
+    return $manager;
+  }
+
+  /**
+   * Integration test for local tasks.
+   *
+   * @param $route_name
+   *   Route name to base task building on.
+   * @param $expected_tasks
+   *   A list of tasks groups by level expected at the given route
+   * @param array $route_params
+   *   (optional) a list of route parameters used to resolve tasks.
+   */
+  protected function assertLocalTasks($route_name, $expected_tasks, $route_params = array()) {
+
+    $manager = $this->getLocalTaskManager($this->moduleList, $route_name, $route_params);
+
+    $tmp_tasks = $manager->getLocalTasksForRoute($route_name);
+
+    // At this point we're just testing existence so pull out keys and then compare.
+    //
+    // Deeper testing would require a functioning factory which because we're using
+    // the DefaultPluginManager base means we get into dependency soup because of
+    // its factories create method and pulling services off the \Drupal container.
+    $tasks = array();
+    foreach ($tmp_tasks as $level => $level_tasks) {
+      $tasks[$level] = array_keys($level_tasks);
+    }
+    $this->assertEquals($expected_tasks, $tasks);
+  }
+}
