diff --git a/core/modules/system/tests/src/Functional/Cache/AssertPageCacheContextsAndTagsTrait.php b/core/modules/system/tests/src/Functional/Cache/AssertPageCacheContextsAndTagsTrait.php
index 1cc2cad..969e794 100644
--- a/core/modules/system/tests/src/Functional/Cache/AssertPageCacheContextsAndTagsTrait.php
+++ b/core/modules/system/tests/src/Functional/Cache/AssertPageCacheContextsAndTagsTrait.php
@@ -134,7 +134,7 @@ protected function assertCacheTags(array $expected_tags, $include_default_tags =
    */
   protected function assertCacheContexts(array $expected_contexts, $message = NULL, $include_default_contexts = TRUE) {
     if ($include_default_contexts) {
-      $default_contexts = ['languages:language_interface', 'theme'];
+      $default_contexts = ['languages:language_interface', 'route', 'theme'];
       // Add the user.permission context to the list of default contexts except
       // when user is already there.
       if (!in_array('user', $expected_contexts)) {
diff --git a/core/modules/toolbar/src/Controller/ToolbarController.php b/core/modules/toolbar/src/Controller/ToolbarController.php
index c94e35b..6405955 100644
--- a/core/modules/toolbar/src/Controller/ToolbarController.php
+++ b/core/modules/toolbar/src/Controller/ToolbarController.php
@@ -90,7 +90,11 @@ public static function preRenderAdministrationTray(array $element) {
    * @internal
    */
   public static function preRenderGetRenderedSubtrees(array $data) {
+    $output = '';
+    /** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */
     $menu_tree = \Drupal::service('toolbar.menu_tree');
+    /** @var \Drupal\Core\Menu\LocalTaskManagerInterface $local_task_manager */
+    $local_task_manager = \Drupal::service('plugin.manager.menu.local_task');
     // Load the administration menu. The first level is the "Administration"
     // link. In order to load the children of that link and the subsequent two
     // levels, start at the second level and end at the fourth.
@@ -108,13 +112,97 @@ public static function preRenderGetRenderedSubtrees(array $data) {
     // Calculated the combined cacheability of all subtrees.
     $cacheability = new CacheableMetadata();
     foreach ($tree as $element) {
+      // Get local tasks for this menu item and build render array.
+      $local_tasks = $local_task_manager->getTasksBuild($element->link->getRouteName(), $cacheability);
       /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
       $link = $element->link;
       if ($element->subtree) {
         $subtree = $menu_tree->build($element->subtree);
+        if (count($local_tasks)) {
+          // Reduce the local tasks tree by elements already in the admin menu
+          // tree.
+          $local_tasks_subtree_reduced = [];
+          foreach ($local_tasks as $key => $tasks) {
+            foreach ($local_tasks[$key] as $task_key => $task) {
+              if (!isset($subtree['#items'][$task_key]) && $task_key != $element->link->getRouteName()) {
+                $local_tasks_subtree_reduced[$key][$task_key] = $task;
+              }
+            }
+          }
+          // Merge the local tasks into the existing 2nd level subtree.
+          if (count($local_tasks_subtree_reduced)) {
+            $local_tasks_subtree_build = _build_tasks_as_menu_tree($local_tasks_subtree_reduced);
+            $subtree['#items'] += $local_tasks_subtree_build['#items'];
+          }
+        }
+        foreach ($element->subtree as $sub_element) {
+          // Get local tasks for this sub menu item and build render array.
+          $sub_local_tasks = $local_task_manager->getTasksBuild($sub_element->link->getRouteName(), $cacheability);
+          $route_name = $sub_element->link->getRouteName();
+          $route_name_parent = $element->link->getRouteName();
+          if (count($sub_local_tasks)) {
+            $sub_local_tasks_subtree_reduced = [];
+            if (count($sub_element->subtree)) {
+              // Reduce the local tasks tree by elements already in the admin
+              // menu tree.
+              foreach ($sub_local_tasks as $key => $tasks) {
+                foreach ($sub_local_tasks[$key] as $task_key => $task) {
+                  if (!isset($subtree['#items'][$task_key])
+                  && !isset($subtree['#items'][$route_name]['below'][$task_key])
+                  && $task_key != $route_name
+                  && $task_key != $route_name_parent) {
+                    $sub_local_tasks_subtree_reduced[$key][$task_key] = $task;
+                  }
+                }
+              }
+              // Merge the local tasks into the existing 3rd level subtree.
+              if (count(current($sub_local_tasks_subtree_reduced))) {
+                $sub_local_tasks_subtree_build = _build_tasks_as_menu_tree($sub_local_tasks_subtree_reduced);
+                $subtree['#items'][$route_name]['below'] += $sub_local_tasks_subtree_build['#items'];
+              }
+            }
+            else {
+              // Reduce the local tasks tree by elements already in the admin
+              // menu tree.
+              foreach ($sub_local_tasks as $key => $tasks) {
+                foreach ($sub_local_tasks[$key] as $task_key => $task) {
+                  if (!isset($subtree['#items'][$task_key]) && $task_key != $route_name && $task_key != $route_name_parent) {
+                    $sub_local_tasks_subtree_reduced[$key][$task_key] = $task;
+                  }
+                }
+              }
+              // Add the local tasks as new 3rd level subtree.
+              if (!empty(current($sub_local_tasks_subtree_reduced))) {
+                $sub_local_tasks_subtree_build = _build_tasks_as_menu_tree($sub_local_tasks_subtree_reduced);
+                $subtree['#items'][$route_name]['below'] = $sub_local_tasks_subtree_build['#items'];
+              }
+            }
+          }
+        }
         $output = \Drupal::service('renderer')->renderPlain($subtree);
         $cacheability = $cacheability->merge(CacheableMetadata::createFromRenderArray($subtree));
       }
+      elseif (count($local_tasks)) {
+        // Reduce the local tasks tree by elements already in the admin menu
+        // tree.
+        $local_tasks_subtree_reduced = [];
+        foreach ($local_tasks as $key => $tasks) {
+          foreach ($local_tasks[$key] as $task_key => $task) {
+            if ($task_key != $element->link->getRouteName()) {
+              $local_tasks_subtree_reduced[$key][$task_key] = $task;
+            }
+          }
+        }
+        // Add the local tasks as new 2nd level subtree.
+        if (count($local_tasks_subtree_reduced)) {
+          $local_tasks_subtree_build = _build_tasks_as_menu_tree($local_tasks_subtree_reduced);
+          $output = \Drupal::service('renderer')->renderPlain($local_tasks_subtree_build);
+          $cacheability = $cacheability->merge(CacheableMetadata::createFromRenderArray($local_tasks_subtree_build));
+        }
+        else {
+          $output = '';
+        }
+      }
       else {
         $output = '';
       }
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 483a30b..c95bba2 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -290,3 +290,30 @@ function _toolbar_get_subtrees_hash() {
   $hash = Crypt::hashBase64(serialize($subtrees));
   return [$hash, $cacheability];
 }
+
+/**
+ * Generates a toolbar menu tree from a given tree of local tasks.
+ *
+ * @param \Drupal\Core\Menu\LocalTaskInterface[] $tree
+ *   An array of task levels.
+ *
+ * @return array
+ *   A render array representing the menu tree.
+ */
+function _build_tasks_as_menu_tree($tree) {
+  $menu_tree = [
+    '#sorted' => TRUE,
+    '#theme' => 'menu__toolbar__admin',
+    '#items' => []
+  ];
+  foreach ($tree as $level => $instances) {
+    foreach ($instances as $plugin_id => $child) {
+      // Only 1st level of local tasks will be rendered.
+      if ($level == 0) {
+        $menu_tree['#items'][$plugin_id] = $child['#link'];
+      }
+    }
+  }
+
+  return $menu_tree;
+}
