diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 0d17aa3..216a66b 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Core\Access\AccessManager;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\NullBackend;
 use Drupal\Core\Controller\ControllerResolverInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
diff --git a/core/modules/comment/comment.local_tasks.yml b/core/modules/comment/comment.local_tasks.yml
index 3119823..baba52c 100644
--- a/core/modules/comment/comment.local_tasks.yml
+++ b/core/modules/comment/comment.local_tasks.yml
@@ -13,3 +13,21 @@ comment.confirm_delete_tab:
   tab_root_id: comment.permalink_tab
   weight: 10
 
+comment.admin:
+  title: Comments
+  route_name: comment.admin
+  tab_root_id: node.content_overview
+
+comment.admin_new:
+  title: 'Published comments'
+  route_name: comment.admin
+  tab_root_id: node.content_overview
+  tab_parent_id: comment.admin
+
+comment.admin_approval:
+  title: 'Unapproved comments'
+  route_name: comment.admin_approval
+  class: Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments
+  tab_root_id: node.content_overview
+  tab_parent_id: comment.admin
+  weight: 1
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 166f6b7..1c7e2f1 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -210,18 +210,7 @@ function comment_menu() {
     'title' => 'Comments',
     'description' => 'List and edit site comments and the comment approval queue.',
     'route_name' => 'comment.admin',
-    'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
-  );
-  // Tabs begin here.
-  $items['admin/content/comment/new'] = array(
-    'title' => 'Published comments',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/content/comment/approval'] = array(
-    'title' => 'Unapproved comments',
-    'title callback' => 'comment_count_unpublished',
-    'route_name' => 'comment.admin_approval',
-    'type' => MENU_LOCAL_TASK,
+    'type' => MENU_NORMAL_ITEM,
   );
 
   return $items;
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Menu/LocalTask/UnapprovedComments.php b/core/modules/comment/lib/Drupal/comment/Plugin/Menu/LocalTask/UnapprovedComments.php
new file mode 100644
index 0000000..a92fe71
--- /dev/null
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/Menu/LocalTask/UnapprovedComments.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments.
+ */
+
+namespace Drupal\comment\Plugin\Menu\LocalTask;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Menu\LocalTaskDefault;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a local task that shows the amount of unapproved comments
+ */
+class UnapprovedComments extends LocalTaskDefault implements ContainerFactoryPluginInterface {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a new UnapprovedComments instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, Connection $database) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->database = $database;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('database')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTitle() {
+    $count = $this->database->query('SELECT COUNT(cid) FROM {comment} WHERE status = :status', array(
+      ':status' => COMMENT_NOT_PUBLISHED,
+    ))->fetchField();
+    return $this->t('Unapproved comments (@count)', array('@count' => $count));
+  }
+
+}
diff --git a/core/modules/node/node.local_tasks.yml b/core/modules/node/node.local_tasks.yml
index 24d9ef2..eb7105c 100644
--- a/core/modules/node/node.local_tasks.yml
+++ b/core/modules/node/node.local_tasks.yml
@@ -16,3 +16,7 @@ node.revision_overview:
   tab_root_id: node.view
   title: 'Revisions'
   weight: 20
+node.content_overview:
+  title: Content
+  route_name: node.content_overview
+  tab_root_id: node.content_overview
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 4fe1645..9b8cd78 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -934,10 +934,6 @@ function node_menu() {
     'route_name' => 'node.content_overview',
     'weight' => -10,
   );
-  $items['admin/content/node'] = array(
-    'title' => 'Content',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
 
   $items['admin/structure/types'] = array(
     'title' => 'Content types',
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php
new file mode 100644
index 0000000..f5be097
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\Derivative\ViewsLocalTask.
+ */
+
+namespace Drupal\views\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DerivativeBase;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
+use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\views\Views;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides local task definitions for all views configured as local tasks.
+ */
+class ViewsLocalTask extends DerivativeBase implements ContainerDerivativeInterface {
+
+  /**
+   * The route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface
+   */
+  protected $routeProvider;
+
+  /**
+   * The state key value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $state;
+
+  /**
+   * Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
+   *
+   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
+   *   The route provider.
+   * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state
+   *   The state key value store.
+   */
+  public function __construct(RouteProviderInterface $route_provider, KeyValueStoreInterface $state) {
+    $this->routeProvider = $route_provider;
+    $this->state = $state;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('router.route_provider'),
+      $container->get('state')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    $this->derivatives = array();
+
+    $view_route_names = $this->state->get('views.view_route_names');
+    foreach ($this->getApplicableMenuViews() as $pair) {
+      /** @var $executable \Drupal\views\ViewExecutable */
+      list($executable, $display_id) = $pair;
+
+      $executable->setDisplay($display_id);
+      $menu = $executable->display_handler->getOption('menu');
+      if (in_array($menu['type'], array('tab', 'default tab'))) {
+        $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
+        $route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
+
+        // Don't add a local task for views which override existing routes.
+        // @todo Alternative it could just change the existing entry.
+        if ($route_name != $plugin_id) {
+          continue;
+        }
+
+        $this->derivatives[$plugin_id] = array(
+          'route_name' => $route_name,
+          'weight' => $menu['weight'],
+          'title' => $menu['title'],
+        ) + $base_plugin_definition;
+
+        // Default local tasks have themselves as tab root id.
+        if ($menu['type'] == 'default tab') {
+          $this->derivatives[$plugin_id]['tab_root_id'] = 'views_view:' . $plugin_id;
+        }
+      }
+    }
+    return $this->derivatives;
+  }
+
+  /**
+   * Alters tab_root_id and tab_parent_id into the views local tasks.
+   */
+  public function alterLocalTasks(&$local_tasks) {
+    $view_route_names = $this->state->get('views.view_route_names');
+
+    foreach ($this->getApplicableMenuViews() as $pair) {
+      /** @var $executable \Drupal\views\ViewExecutable */
+      list($executable, $display_id) = $pair;
+
+      $executable->setDisplay($display_id);
+      $menu = $executable->display_handler->getOption('menu');
+
+      // We already have set the tab_root_id for default tabs.
+      if (in_array($menu['type'], array('tab'))) {
+        $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
+        $view_route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
+
+        // Don't add a local task for views which override existing routes.
+        if ($view_route_name != $plugin_id) {
+          unset($local_tasks[$plugin_id]);
+          continue;
+        }
+
+        // Find out the parent route.
+        // @todo Find out how to find both the root and parent tab.
+        $path = $executable->display_handler->getPath();
+        $split = explode('/', $path);
+        array_pop($split);
+        $path = implode('/', $split);
+
+        $pattern = '/' . str_replace('%', '{}', $path);
+        if ($routes = $this->routeProvider->getRoutesByPattern($pattern)) {
+          foreach ($routes->all() as $name => $route) {
+            if ($parent_task = $this->getPluginIdFromRoute($name, $local_tasks)) {
+              $local_tasks['views_view:' . $plugin_id]['tab_root_id'] = $parent_task;
+            }
+            // Skip after the first found route.
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Find the local task ID of the parent route given the route name.
+   *
+   * @param string $route_name
+   *   The route name of the parent local task.
+   * @param array $local_tasks
+   *   An array of all local task definitions.
+   *
+   * @return NULL|string
+   *   Returns the local task ID of the parent task, otherwise NULL.
+   */
+  protected function getPluginIdFromRoute($route_name, &$local_tasks) {
+    $local_task_id = NULL;
+    foreach ($local_tasks as $plugin_id => $local_task) {
+      if ($local_task['route_name'] == $route_name) {
+        $local_task_id = $plugin_id;
+        break;
+      }
+    }
+
+    return $local_task_id;
+  }
+
+  /**
+   * Return a list of all views and display IDs that have a menu entry.
+   *
+   * @return array
+   *   A list of arrays containing the $view and $display_id.
+   * @code
+   * array(
+   *   array($view, $display_id),
+   *   array($view, $display_id),
+   * );
+   * @endcode
+   */
+  protected function getApplicableMenuViews() {
+    return Views::getApplicableViews('uses_hook_menu');
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index 731f604..502fbeb 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -294,17 +294,22 @@ public function executeHookMenu($callbacks) {
           $items[$path]['menu_name'] = $menu['name'];
           break;
         case 'tab':
-          $items[$path]['type'] = MENU_LOCAL_TASK;
+          $items[$path]['type'] = MENU_CALLBACK;
           break;
         case 'default tab':
-          $items[$path]['type'] = MENU_DEFAULT_LOCAL_TASK;
+          $items[$path]['type'] = MENU_CALLBACK;
           break;
       }
 
       // Add context for contextual links.
       // @see menu_contextual_links()
-      if (!empty($menu['context'])) {
-        $items[$path]['context'] = MENU_CONTEXT_INLINE;
+      if (in_array($menu['type'], array('tab', 'default tab'))) {
+        // @todo Remove once contextual links are ported to a new plugin based
+        //   system.
+        if (!empty($menu['context'])) {
+          $items[$path]['context'] = MENU_CONTEXT_INLINE;
+          $items[$path]['type'] = MENU_LOCAL_TASK;
+        }
       }
 
       // If this is a 'default' tab, check to see if we have to create the
@@ -316,6 +321,11 @@ public function executeHookMenu($callbacks) {
         // Remove the last piece.
         $bit = array_pop($bits);
 
+        // Default tabs are handled by the local task plugins.
+        if ($tab_options['type'] == 'tab') {
+          return $items;
+        }
+
         // we can't do this if they tried to make the last path bit variable.
         // @todo: We can validate this.
         if ($bit != '%views_arg' && !empty($bits)) {
@@ -339,9 +349,6 @@ public function executeHookMenu($callbacks) {
             case 'normal':
               $items[$default_path]['type'] = MENU_NORMAL_ITEM;
               break;
-            case 'tab':
-              $items[$default_path]['type'] = MENU_LOCAL_TASK;
-              break;
           }
           if (isset($tab_options['weight'])) {
             $items[$default_path]['weight'] = intval($tab_options['weight']);
diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php
new file mode 100644
index 0000000..2b7463d
--- /dev/null
+++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php
@@ -0,0 +1,342 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\Plugin\Derivative\ViewsLocalTaskTest.
+ */
+
+namespace Drupal\views\Tests\Plugin\Derivative;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\Derivative\ViewsLocalTask;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Tests the views local task derivative.
+ *
+ * @see \Drupal\views\Plugin\Derivative\ViewsLocalTask
+ */
+class ViewsLocalTaskTest extends UnitTestCase {
+
+  /**
+   * The mocked route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeProvider;
+
+  /**
+   * The mocked key value storage.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $state;
+
+  protected $baseDefinition = array(
+    'class' => '\Drupal\views\Plugin\Menu\LocalTask\ViewsLocalTask',
+    'derivative' => '\Drupal\views\Plugin\Derivative\ViewsLocalTask'
+  );
+
+  /**
+   * The tested local task derivative class.
+   *
+   * @var \Drupal\views\Plugin\Derivative\ViewsLocalTask
+   */
+  protected $localTaskDerivative;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Views local task derivative',
+      'description' => 'Tests the views local task derivative.',
+      'group' => 'Views plugin',
+    );
+  }
+
+  protected function setUp() {
+    $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+    $this->state = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface');
+
+    $this->localTaskDerivative = new TestViewsLocalTask($this->routeProvider, $this->state);
+  }
+
+  /**
+   * Tests fetching the derivatives on no view with hook menu.
+   *
+   * @see \Drupal\views\Plugin\Derivative\ViewsLocalTask::getDerivativeDefinitions()
+   */
+  public function testGetDerivativeDefinitionsWithoutHookMenuViews() {
+    $result = array();
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    $definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+    $this->assertEquals(array(), $definitions);
+  }
+
+  /**
+   * Tests fetching the derivatives on a view with without a local task.
+   */
+  public function testGetDerivativeDefinitionsWithoutLocalTask() {
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
+      ->setMethods(array('getOption'))
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $display_plugin->expects($this->once())
+      ->method('getOption')
+      ->with('menu')
+      ->will($this->returnValue(array('type' => 'normal')));
+    $executable->display_handler = $display_plugin;
+
+    $result = array(array($executable, 'page_1'));
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    $definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+    $this->assertEquals(array(), $definitions);
+  }
+
+  /**
+   * Tests fetching the derivatives on a view with a default local task.
+   */
+  public function testGetDerivativeDefinitionsWithLocalTask() {
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage = $this->getMockBuilder('Drupal\views\Entity\View')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('example_view'));
+    $executable->storage = $storage;
+
+    $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
+      ->setMethods(array('getOption'))
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $display_plugin->expects($this->once())
+      ->method('getOption')
+      ->with('menu')
+      ->will($this->returnValue(array('type' => 'tab', 'weight' => 12, 'title' => 'Example title')));
+    $executable->display_handler = $display_plugin;
+
+    $result = array(array($executable, 'page_1'));
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    // Mock the view route names state.
+    $view_route_names = array();
+    $view_route_names['example_view.page_1'] = 'view.example_view.page_1';
+    $this->state->expects($this->once())
+      ->method('get')
+      ->with('views.view_route_names')
+      ->will($this->returnValue($view_route_names));
+
+    $definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+    $this->assertCount(1, $definitions);
+    $this->assertEquals('view.example_view.page_1', $definitions['view.example_view.page_1']['route_name']);
+    $this->assertEquals(12, $definitions['view.example_view.page_1']['weight']);
+    $this->assertEquals('Example title', $definitions['view.example_view.page_1']['title']);
+    $this->assertEquals($this->baseDefinition['class'], $definitions['view.example_view.page_1']['class']);
+    $this->assertTrue(empty($definitions['view.example_view.page_1']['tab_root_id']));
+  }
+
+  /**
+   * Tests fetching the derivatives on a view which overrides an existing route.
+   */
+  public function testGetDerivativeDefinitionsWithOverrideRoute() {
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage = $this->getMockBuilder('Drupal\views\Entity\View')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('example_view'));
+    $executable->storage = $storage;
+
+    $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
+      ->setMethods(array('getOption'))
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $display_plugin->expects($this->once())
+      ->method('getOption')
+      ->with('menu')
+      ->will($this->returnValue(array('type' => 'tab', 'weight' => 12)));
+    $executable->display_handler = $display_plugin;
+
+    $result = array(array($executable, 'page_1'));
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    // Mock the view route names state.
+    $view_route_names = array();
+    // Setup a view which overrides an existing route.
+    $view_route_names['example_view.page_1'] = 'example_overridden_route';
+    $this->state->expects($this->once())
+      ->method('get')
+      ->with('views.view_route_names')
+      ->will($this->returnValue($view_route_names));
+
+    $definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+    $this->assertCount(0, $definitions);
+  }
+
+  /**
+   * Tests fetching the derivatives on a view with a default local task.
+   */
+  public function testGetDerivativeDefinitionsWithDefaultLocalTask() {
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage = $this->getMockBuilder('Drupal\views\Entity\View')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('example_view'));
+    $executable->storage = $storage;
+
+    $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
+      ->setMethods(array('getOption'))
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $display_plugin->expects($this->exactly(2))
+      ->method('getOption')
+      ->with('menu')
+      ->will($this->returnValue(array('type' => 'default tab', 'weight' => 12, 'title' => 'Example title')));
+    $executable->display_handler = $display_plugin;
+
+    $result = array(array($executable, 'page_1'));
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    // Mock the view route names state.
+    $view_route_names = array();
+    $view_route_names['example_view.page_1'] = 'view.example_view.page_1';
+    $this->state->expects($this->exactly(2))
+      ->method('get')
+      ->with('views.view_route_names')
+      ->will($this->returnValue($view_route_names));
+
+    $definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+    $this->assertCount(1, $definitions);
+    $plugin = $definitions['view.example_view.page_1'];
+    $this->assertEquals('view.example_view.page_1', $plugin['route_name']);
+    $this->assertEquals(12, $plugin['weight']);
+    $this->assertEquals('Example title', $plugin['title']);
+    $this->assertEquals($this->baseDefinition['class'], $plugin['class']);
+    $this->assertEquals('views_view:view.example_view.page_1', $plugin['tab_root_id']);
+
+    // Setup the prefix of the derivative.
+    $definitions['views_view:view.example_view.page_1'] = $definitions['view.example_view.page_1'];
+    unset($definitions['view.example_view.page_1']);
+    $this->localTaskDerivative->alterLocalTasks($definitions);
+
+    $plugin = $definitions['views_view:view.example_view.page_1'];
+    $this->assertCount(1, $definitions);
+    $this->assertEquals('view.example_view.page_1', $plugin['route_name']);
+    $this->assertEquals(12, $plugin['weight']);
+    $this->assertEquals('Example title', $plugin['title']);
+    $this->assertEquals($this->baseDefinition['class'], $plugin['class']);
+    $this->assertEquals('views_view:view.example_view.page_1', $plugin['tab_root_id']);
+  }
+
+  /**
+   * Tests fetching the derivatives on a view with a local task and a parent.
+   *
+   * The parent is defined by another module, not views.
+   */
+  public function testGetDerivativeDefinitionsWithExistingLocalTask() {
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage = $this->getMockBuilder('Drupal\views\Entity\View')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $storage->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('example_view'));
+    $executable->storage = $storage;
+
+    $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
+      ->setMethods(array('getOption', 'getPath'))
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $display_plugin->expects($this->exactly(2))
+      ->method('getOption')
+      ->with('menu')
+      ->will($this->returnValue(array('type' => 'tab', 'weight' => 12, 'title' => 'Example title')));
+    $display_plugin->expects($this->once())
+      ->method('getPath')
+      ->will($this->returnValue('path/example'));
+    $executable->display_handler = $display_plugin;
+
+    $result = array(array($executable, 'page_1'));
+    $this->localTaskDerivative->setApplicableMenuViews($result);
+
+    // Mock the view route names state.
+    $view_route_names = array();
+    $view_route_names['example_view.page_1'] = 'view.example_view.page_1';
+    $this->state->expects($this->exactly(2))
+      ->method('get')
+      ->with('views.view_route_names')
+      ->will($this->returnValue($view_route_names));
+
+    // Mock the route provider.
+    $route_collection = new RouteCollection();
+    $route_collection->add('test_route', new Route('/path'));
+    $this->routeProvider->expects($this->any())
+      ->method('getRoutesByPattern')
+      ->with('/path')
+      ->will($this->returnValue($route_collection));
+
+    // Setup the existing local task of the test_route.
+    $definitions['test_route_tab'] = $other_tab = array(
+      'route_name' => 'test_route',
+      'title' => 'Test route',
+      'tab_root_id' => 'test_route_tab',
+    );
+
+    $definitions += $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
+
+    // Setup the prefix of the derivative.
+    $definitions['views_view:view.example_view.page_1'] = $definitions['view.example_view.page_1'];
+    unset($definitions['view.example_view.page_1']);
+    $this->localTaskDerivative->alterLocalTasks($definitions);
+
+    $plugin = $definitions['views_view:view.example_view.page_1'];
+    $this->assertCount(2, $definitions);
+
+    // Ensure the other local task was not changed.
+    $this->assertEquals($other_tab, $definitions['test_route_tab']);
+
+    $this->assertEquals('view.example_view.page_1', $plugin['route_name']);
+    $this->assertEquals(12, $plugin['weight']);
+    $this->assertEquals('Example title', $plugin['title']);
+    $this->assertEquals($this->baseDefinition['class'], $plugin['class']);
+    $this->assertEquals('test_route_tab', $plugin['tab_root_id']);
+  }
+
+}
+
+/**
+ * Replaces the applicable views call for easier testability.
+ */
+class TestViewsLocalTask extends ViewsLocalTask {
+
+  /**
+   * Sets applicable views result.
+   */
+  public function setApplicableMenuViews($result) {
+    $this->result = $result;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getApplicableMenuViews() {
+    return $this->result;
+  }
+
+}
diff --git a/core/modules/views/views.local_tasks.yml b/core/modules/views/views.local_tasks.yml
new file mode 100644
index 0000000..f050e64
--- /dev/null
+++ b/core/modules/views/views.local_tasks.yml
@@ -0,0 +1,3 @@
+views_view:
+  class: Drupal\Core\Menu\LocalTaskDefault
+  derivative: \Drupal\views\Plugin\Derivative\ViewsLocalTask
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index edc5ec1..449e864 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -12,6 +12,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\Query\AlterableInterface;
 use Drupal\Core\Language\Language;
+use Drupal\views\Plugin\Derivative\ViewsLocalTask;
 use Drupal\views\ViewExecutable;
 use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\views\Entity\View;
@@ -1600,3 +1601,11 @@ function views_cache_get($cid, $use_language = FALSE) {
   return cache('views_info')->get($cid);
 }
 
+/**
+ * Implements hook_local_tasks_alter().
+ */
+function views_local_tasks_alter(&$local_tasks) {
+  $container = \Drupal::getContainer();
+  $local_task = ViewsLocalTask::create($container, 'views_view');
+  $local_task->alterLocalTasks($local_tasks);
+}
