diff --git a/core/core.services.yml b/core/core.services.yml
index e8b6464e8bc916505f6e420425b984446f3eca59..d2de794128788bc4aacb1a82cb5669d068df520a 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -326,7 +326,7 @@ services:
     arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@state']
   router.rebuild_subscriber:
     class: Drupal\Core\EventSubscriber\RouterRebuildSubscriber
-    arguments: ['@router.builder']
+    arguments: ['@router.builder', '@lock']
     tags:
       - { name: event_subscriber }
   path.alias_manager.cached:
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 1d3adf62fcfe7a71ab20832711f77e62cc22d161..a1c8a01449a671a679608db31a8a02be27040faa 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -5,19 +5,12 @@
  * API for the Drupal menu system.
  */
 
-use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\Language;
-use Drupal\Core\ParamConverter\ParamNotConvertedException;
-use Drupal\Core\Routing\RequestHelper;
 use Drupal\Core\Template\Attribute;
-use Drupal\menu_link\Entity\MenuLink;
 use Drupal\menu_link\MenuLinkInterface;
-use Drupal\menu_link\MenuLinkStorageController;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Route;
 
 /**
  * @defgroup menu Menu and routing system
@@ -44,9 +37,9 @@
  *   the stuff in the routing.yml file means.
  *
  * @section Defining menu links
- * Once you have a route defined, you can use hook_menu() to define links
- * for your module's paths in the main Navigation menu or other menus. See
- * the hook_menu() documentation for more details.
+ * Once you have a route defined, you can use hook_menu_link_defaults() to
+ * define links for your module's paths in the main Navigation menu or other
+ * menus. See the hook_menu_link_defaults() documentation for more details.
  *
  * @todo The rest of this topic has not been reviewed or updated for Drupal 8.x
  *   and is not correct!
@@ -125,11 +118,6 @@
  */
 const MENU_VISIBLE_IN_TREE = 0x0002;
 
-/**
- * Internal menu flag -- menu item is visible in the breadcrumb.
- */
-const MENU_VISIBLE_IN_BREADCRUMB = 0x0004;
-
 /**
  * Internal menu flag -- menu item links back to its parent.
  */
@@ -170,7 +158,7 @@
  * the administrator. Use this for most menu items. It is the default value if
  * no menu item type is specified.
  */
-define('MENU_NORMAL_ITEM', MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB);
+define('MENU_NORMAL_ITEM', MENU_VISIBLE_IN_TREE);
 
 /**
  * Menu type -- A hidden, internal callback, typically used for API calls.
@@ -188,76 +176,18 @@
  * Note for the value: 0x0010 was a flag which is no longer used, but this way
  * the values of MENU_CALLBACK and MENU_SUGGESTED_ITEM are separate.
  */
-define('MENU_SUGGESTED_ITEM', MENU_VISIBLE_IN_BREADCRUMB | 0x0010);
-
-/**
- * Menu type -- A task specific to the parent item, usually rendered as a tab.
- *
- * Local tasks are menu items that describe actions to be performed on their
- * parent item. An example is the path "node/52/edit", which performs the
- * "edit" task on "node/52".
- */
-define('MENU_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_VISIBLE_IN_BREADCRUMB);
-
-/**
- * Menu type -- The "default" local task, which is initially active.
- *
- * Every set of local tasks should provide one "default" task, that links to the
- * same path as its parent when clicked.
- */
-define('MENU_DEFAULT_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_LINKS_TO_PARENT | MENU_VISIBLE_IN_BREADCRUMB);
-
-/**
- * Menu type -- A task specific to the parent, which is never rendered.
- *
- * Sibling local tasks are not rendered themselves, but affect the active
- * trail and need their sibling tasks rendered as tabs.
- */
-define('MENU_SIBLING_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_VISIBLE_IN_BREADCRUMB);
+define('MENU_SUGGESTED_ITEM', 0x0010);
 
 /**
  * @} End of "defgroup menu_item_types".
  */
 
-/**
- * @defgroup menu_context_types Menu context types
- * @{
- * Flags for use in the "context" attribute of menu router items.
- */
-
-/**
- * Internal menu flag: Invisible local task.
- *
- * This flag may be used for local tasks like "Delete", so custom modules and
- * themes can alter the default context and expose the task by altering menu.
- */
-const MENU_CONTEXT_NONE = 0x0000;
-
-/**
- * Internal menu flag: Local task should be displayed in page context.
- */
-const MENU_CONTEXT_PAGE = 0x0001;
-
-/**
- * @} End of "defgroup menu_context_types".
- */
-
 /**
  * @defgroup menu_status_codes Menu status codes
  * @{
  * Status codes for menu callbacks.
  */
 
-/**
- * Internal menu status code -- Menu item was not found.
- */
-const MENU_NOT_FOUND = 404;
-
-/**
- * Internal menu status code -- Menu item access is denied.
- */
-const MENU_ACCESS_DENIED = 403;
-
 /**
  * Internal menu status code -- Menu item inaccessible because site is offline.
  */
@@ -278,12 +208,6 @@
  * Parameters for a menu tree.
  */
 
- /**
- * The maximum number of path elements for a menu callback
- */
-const MENU_MAX_PARTS = 9;
-
-
 /**
  * The maximum depth of a menu links tree - matches the number of p columns.
  *
@@ -312,260 +236,17 @@
 const MENU_PREFERRED_LINK = '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91';
 
 /**
- * Returns the ancestors (and relevant placeholders) for any given path.
- *
- * For example, the ancestors of node/12345/edit are:
- * - node/12345/edit
- * - node/12345/%
- * - node/%/edit
- * - node/%/%
- * - node/12345
- * - node/%
- * - node
- *
- * To generate these, we will use binary numbers. Each bit represents a
- * part of the path. If the bit is 1, then it represents the original
- * value while 0 means wildcard. If the path is node/12/edit/foo
- * then the 1011 bitstring represents node/%/edit/foo where % means that
- * any argument matches that part. We limit ourselves to using binary
- * numbers that correspond the patterns of wildcards of router items that
- * actually exists. This list of 'masks' is built in menu_router_rebuild().
- *
- * @param $parts
- *   An array of path parts, for the above example
- *   array('node', '12345', 'edit').
- *
- * @return
- *   An array which contains the ancestors and placeholders. Placeholders
- *   simply contain as many '%s' as the ancestors.
- */
-function menu_get_ancestors($parts) {
-  $number_parts = count($parts);
-  $ancestors = array();
-  $length =  $number_parts - 1;
-  $end = (1 << $number_parts) - 1;
-  $masks = \Drupal::state()->get('menu.masks');
-  // If the optimized menu.masks array is not available use brute force to get
-  // the correct $ancestors and $placeholders returned. Do not use this as the
-  // default value of the menu.masks variable to avoid building such a big
-  // array.
-  if (!$masks) {
-    $masks = range(511, 1);
-  }
-  // Only examine patterns that actually exist as router items (the masks).
-  foreach ($masks as $i) {
-    if ($i > $end) {
-      // Only look at masks that are not longer than the path of interest.
-      continue;
-    }
-    elseif ($i < (1 << $length)) {
-      // We have exhausted the masks of a given length, so decrease the length.
-      --$length;
-    }
-    $current = '';
-    for ($j = $length; $j >= 0; $j--) {
-      // Check the bit on the $j offset.
-      if ($i & (1 << $j)) {
-        // Bit one means the original value.
-        $current .= $parts[$length - $j];
-      }
-      else {
-        // Bit zero means means wildcard.
-        $current .= '%';
-      }
-      // Unless we are at offset 0, add a slash.
-      if ($j) {
-        $current .= '/';
-      }
-    }
-    $ancestors[] = $current;
-  }
-  return $ancestors;
-}
-
-/**
- * Unserializes menu data, using a map to replace path elements.
- *
- * The menu system stores various path-related information (such as the 'page
- * arguments' and 'access arguments' components of a menu item) in the database
- * using serialized arrays, where integer values in the arrays represent
- * arguments to be replaced by values from the path. This function first
- * unserializes such menu information arrays, and then does the path
- * replacement.
- *
- * The path replacement acts on each integer-valued element of the unserialized
- * menu data array ($data) using a map array ($map, which is typically an array
- * of path arguments) as a list of replacements. For instance, if there is an
- * element of $data whose value is the number 2, then it is replaced in $data
- * with $map[2]; non-integer values in $data are left alone.
- *
- * As an example, an unserialized $data array with elements ('node_load', 1)
- * represents instructions for calling the node_load() function. Specifically,
- * this instruction says to use the path component at index 1 as the input
- * parameter to node_load(). If the path is 'node/123', then $map will be the
- * array ('node', 123), and the returned array from this function will have
- * elements ('node_load', 123), since $map[1] is 123. This return value will
- * indicate specifically that node_load(123) is to be called to load the node
- * whose ID is 123 for this menu item.
- *
- * @param $data
- *   A serialized array of menu data, as read from the database.
- * @param $map
- *   A path argument array, used to replace integer values in $data; an integer
- *   value N in $data will be replaced by value $map[N]. Typically, the $map
- *   array is generated from a call to the arg() function.
- *
- * @return
- *   The unserialized $data array, with path arguments replaced.
- */
-function menu_unserialize($data, $map) {
-  if ($data = unserialize($data)) {
-    foreach ($data as $k => $v) {
-      if (is_int($v)) {
-        $data[$k] = isset($map[$v]) ? $map[$v] : '';
-      }
-    }
-    return $data;
-  }
-  else {
-    return array();
-  }
-}
-
-/**
- * Loads objects into the map as defined in the $item['load_functions'].
- *
- * @param $item
- *   A menu router or menu link item
- * @param $map
- *   An array of path arguments; for example, array('node', '5').
- *
- * @return
- *   Returns TRUE for success, FALSE if an object cannot be loaded.
- *   Names of object loading functions are placed in $item['load_functions'].
- *   Loaded objects are placed in $map[]; keys are the same as keys in the
- *   $item['load_functions'] array.
- *   $item['access'] is set to FALSE if an object cannot be loaded.
- */
-function _menu_load_objects(&$item, &$map) {
-  if ($load_functions = $item['load_functions']) {
-    // If someone calls this function twice, then unserialize will fail.
-    if (!is_array($load_functions)) {
-      $load_functions = unserialize($load_functions);
-    }
-    $path_map = $map;
-    foreach ($load_functions as $index => $function) {
-      if ($function) {
-        $value = isset($path_map[$index]) ? $path_map[$index] : '';
-        if (is_array($function)) {
-          // Set up arguments for the load function. These were pulled from
-          // 'load arguments' in the hook_menu() entry, but they need
-          // some processing. In this case the $function is the key to the
-          // load_function array, and the value is the list of arguments.
-          list($function, $args) = each($function);
-          $load_functions[$index] = $function;
-
-          // Some arguments are placeholders for dynamic items to process.
-          foreach ($args as $i => $arg) {
-            if ($arg === '%index') {
-              // Pass on argument index to the load function, so multiple
-              // occurrences of the same placeholder can be identified.
-              $args[$i] = $index;
-            }
-            if ($arg === '%map') {
-              // Pass on menu map by reference. The accepting function must
-              // also declare this as a reference if it wants to modify
-              // the map.
-              $args[$i] = &$map;
-            }
-            if (is_int($arg)) {
-              $args[$i] = isset($path_map[$arg]) ? $path_map[$arg] : '';
-            }
-          }
-          array_unshift($args, $value);
-          $return = call_user_func_array($function, $args);
-        }
-        else {
-          $return = $function($value);
-        }
-        // If callback returned an error or there is no callback, trigger 404.
-        if (empty($return)) {
-          $item['access'] = FALSE;
-          $map = FALSE;
-          return FALSE;
-        }
-        $map[$index] = $return;
-      }
-    }
-    $item['load_functions'] = $load_functions;
-  }
-  return TRUE;
-}
-
-/**
- * Checks access to a menu item using the access callback.
- *
- * @param $item
- *   A menu router or menu link item
- * @param $map
- *   An array of path arguments; for example, array('node', '5').
- *
- * @return
- *   $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
- */
-function _menu_check_access(&$item, $map) {
-  // Determine access callback, which will decide whether or not the current
-  // user has access to this path.
-  $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
-  // Check for a TRUE or FALSE value.
-  if (is_numeric($callback)) {
-    $item['access'] = (bool) $callback;
-  }
-  else {
-    $arguments = menu_unserialize($item['access_arguments'], $map);
-    // As call_user_func_array is quite slow and user_access is a very common
-    // callback, it is worth making a special case for it.
-    if ($callback == 'user_access') {
-      $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
-    }
-    else {
-      $item['access'] = call_user_func_array($callback, $arguments);
-    }
-  }
-}
-
-/**
- * Localizes the router item title using t() or another callback.
+ * Localizes a menu link title using t() if possible.
  *
  * Translate the title and description to allow storage of English title
  * strings in the database, yet display of them in the language required
  * by the current user.
  *
  * @param $item
- *   A menu router item or a menu link item.
- * @param $map
- *   The path as an array with objects already replaced. E.g., for path
- *   node/123 $map would be array('node', $node) where $node is the node
- *   object for node 123.
- * @param $link_translate
- *   TRUE if we are translating a menu link item; FALSE if we are
- *   translating a menu router item.
- *
- * @return
- *   No return value.
- *   $item['title'] is localized according to $item['title_callback'].
- *   If an item's callback is check_plain(), $item['options']['html'] becomes
- *   TRUE.
- *   $item['description'] is computed using $item['description_callback'] if
- *   specified; otherwise it is translated using t().
- *   When doing link translation and the $item['options']['attributes']['title']
- *   (link title attribute) matches the description, it is translated as well.
- */
-function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
+ *   A menu link entity.
+ */
+function _menu_item_localize(&$item) {
   // Allow default menu links to be translated.
-  // @todo Figure out a proper way to support translations of menu links, see
-  //   https://drupal.org/node/2193777.
-  $title_callback = $item instanceof MenuLinkInterface && !$item->customized ? 't' :  $item['title_callback'];
   $item['localized_options'] = $item['options'];
   // All 'class' attributes are assumed to be an array during rendering, but
   // links stored in the database may use an old string value.
@@ -575,221 +256,20 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
   if (isset($item['options']['attributes']['class']) && is_string($item['options']['attributes']['class'])) {
     $item['localized_options']['attributes']['class'] = explode(' ', $item['options']['attributes']['class']);
   }
-  // If we are translating the title of a menu link, and its title is the same
-  // as the corresponding router item, then we can use the title information
-  // from the router. If it's customized, then we need to use the link title
-  // itself; can't localize.
-  // If we are translating a router item (tabs, page, breadcrumb), then we
-  // can always use the information from the router item.
-  if (!$link_translate || !isset($item['link_title']) || ($item['title'] == $item['link_title'])) {
-    // t() is a special case. Since it is used very close to all the time,
-    // we handle it directly instead of using indirect, slower methods.
-    // @todo Recheck this line once https://drupal.org/node/2084421 is in.
-    $item['title'] = isset($item['link_title']) ? $item['link_title'] : $item['title'];
-    if ($title_callback == 't') {
-      if (empty($item['title_arguments'])) {
-        $item['title'] = t($item['title']);
-      }
-      else {
-        $item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map));
-      }
-    }
-    elseif ($title_callback) {
-      if (empty($item['title_arguments'])) {
-        $item['title'] = $title_callback($item['title']);
-      }
-      else {
-        $item['title'] = call_user_func_array($title_callback, menu_unserialize($item['title_arguments'], $map));
-      }
-      // Avoid calling check_plain again on l() function.
-      if ($title_callback == 'check_plain') {
-        $item['localized_options']['html'] = TRUE;
-      }
-    }
-  }
-  elseif ($link_translate) {
-    $item['title'] = $item['link_title'];
-  }
-
-  // Translate description, see the motivation above.
-  if (!empty($item['description'])) {
-    $original_description = $item['description'];
-  }
-  if (!empty($item['description_arguments']) || !empty($item['description'])) {
-    $description_callback = $item['description_callback'];
-    // If the description callback is t(), call it directly.
-    if ($description_callback == 't') {
-      if (empty($item['description_arguments'])) {
-        $item['description'] = t($item['description']);
-      }
-      else {
-        $item['description'] = t($item['description'], menu_unserialize($item['description_arguments'], $map));
-      }
-    }
-    elseif ($description_callback) {
-      // If there are no arguments, call the description callback directly.
-      if (empty($item['description_arguments'])) {
-        $item['description'] = $description_callback($item['description']);
-      }
-      // Otherwise, use call_user_func_array() to pass the arguments.
-      else {
-        $item['description'] = call_user_func_array($description_callback, menu_unserialize($item['description_arguments'], $map));
-      }
-    }
-  }
-  // If the title and description are the same, use the translated description
-  // as a localized title.
-  if ($link_translate && isset($original_description) && isset($item['options']['attributes']['title']) && $item['options']['attributes']['title'] == $original_description) {
-    $item['localized_options']['attributes']['title'] = $item['description'];
-  }
-}
-
-/**
- * Handles dynamic path translation and menu access control.
- *
- * When a user arrives on a page such as node/5, this function determines
- * what "5" corresponds to, by inspecting the page's menu path definition,
- * node/%node. This will call node_load(5) to load the corresponding node
- * object.
- *
- * It also works in reverse, to allow the display of tabs and menu items which
- * contain these dynamic arguments, translating node/%node to node/5.
- *
- * Translation of menu item titles and descriptions are done here to
- * allow for storage of English strings in the database, and translation
- * to the language required to generate the current page.
- *
- * @param $router_item
- *   A menu router item
- * @param $map
- *   An array of path arguments; for example, array('node', '5').
- * @param $to_arg
- *   Execute $item['to_arg_functions'] or not. Use only if you want to render a
- *   path from the menu table, for example tabs.
- *
- * @return
- *   Returns the map with objects loaded as defined in the
- *   $item['load_functions']. $item['access'] becomes TRUE if the item is
- *   accessible, FALSE otherwise. $item['href'] is set according to the map.
- *   If an error occurs during calling the load_functions (like trying to load
- *   a non-existent node) then this function returns FALSE.
- */
-function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
-  if ($to_arg && !empty($router_item['to_arg_functions'])) {
-    // Fill in missing path elements, such as the current uid.
-    _menu_link_map_translate($map, $router_item['to_arg_functions']);
-  }
-  // The $path_map saves the pieces of the path as strings, while elements in
-  // $map may be replaced with loaded objects.
-  $path_map = $map;
-  if (!empty($router_item['load_functions']) && !_menu_load_objects($router_item, $map)) {
-    // An error occurred loading an object.
-    $router_item['access'] = FALSE;
-    return FALSE;
-  }
-  // Avoid notices until we remove this function.
-  // @see https://drupal.org/node/2107533
-  $tab_root_map = array();
-  $tab_parent_map = array();
-  // Generate the link path for the page request or local tasks.
-  $link_map = explode('/', $router_item['path']);
-  if (isset($router_item['tab_root'])) {
-    $tab_root_map = explode('/', $router_item['tab_root']);
-  }
-  if (isset($router_item['tab_parent'])) {
-    $tab_parent_map = explode('/', $router_item['tab_parent']);
-  }
-  for ($i = 0; $i < $router_item['number_parts']; $i++) {
-    if ($link_map[$i] == '%') {
-      $link_map[$i] = $path_map[$i];
-    }
-    if (isset($tab_root_map[$i]) && $tab_root_map[$i] == '%') {
-      $tab_root_map[$i] = $path_map[$i];
-    }
-    if (isset($tab_parent_map[$i]) && $tab_parent_map[$i] == '%') {
-      $tab_parent_map[$i] = $path_map[$i];
-    }
-  }
-  $router_item['href'] = implode('/', $link_map);
-  $router_item['tab_root_href'] = implode('/', $tab_root_map);
-  $router_item['tab_parent_href'] = implode('/', $tab_parent_map);
-  $router_item['options'] = array();
-  if (!empty($router_item['route_name'])) {
-    // Route-provided menu items do not have menu loaders, so replace the map
-    // with the link map.
-    $map = $link_map;
-
-    $route_provider = \Drupal::getContainer()->get('router.route_provider');
-    $route = $route_provider->getRouteByName($router_item['route_name']);
-    $router_item['access'] = menu_item_route_access($route, $router_item['href'], $map);
+  // If the menu link is defined in code and not customized, we can use t().
+  if (!empty($item['machine_name']) && !$item['customized']) {
+    // @todo Figure out a proper way to support translations of menu links, see
+    //   https://drupal.org/node/2193777.
+    $item['title'] = t($item['link_title']);
   }
   else {
-    // @todo: Remove once all routes are converted.
-    _menu_check_access($router_item, $map);
-  }
-
-  // For performance, don't localize an item the user can't access.
-  if ($router_item['access']) {
-    _menu_item_localize($router_item, $map);
-  }
-
-  return $map;
-}
-
-/**
- * Translates the path elements in the map using any to_arg helper function.
- *
- * @param $map
- *   An array of path arguments; for example, array('node', '5').
- * @param $to_arg_functions
- *   An array of helper functions; for example, array(2 => 'menu_tail_to_arg').
- *
- * @see hook_menu()
- */
-function _menu_link_map_translate(&$map, $to_arg_functions) {
-  $to_arg_functions = unserialize($to_arg_functions);
-  foreach ($to_arg_functions as $index => $function) {
-    // Translate place-holders into real values.
-    $arg = $function(!empty($map[$index]) ? $map[$index] : '', $map, $index);
-    if (!empty($map[$index]) || isset($arg)) {
-      $map[$index] = $arg;
-    }
-    else {
-      unset($map[$index]);
-    }
+    $item['title'] = $item['link_title'];
   }
 }
 
-/**
- * Returns a string containing the path relative to the current index.
- */
-function menu_tail_to_arg($arg, $map, $index) {
-  return implode('/', array_slice($map, $index));
-}
-
-/**
- * Loads the path as one string relative to the current index.
- *
- * To use this load function, you must specify the load arguments
- * in the router item as:
- * @code
- * $item['load arguments'] = array('%map', '%index');
- * @endcode
- *
- * @see search_menu().
- */
-function menu_tail_load($arg, &$map, $index) {
-  $arg = implode('/', array_slice($map, $index));
-  $map = array_slice($map, 0, $index);
-  return $arg;
-}
-
 /**
  * Provides menu link unserializing, access control, and argument handling.
  *
- * This function is similar to _menu_translate(), but it also does
- * link-specific preparation (such as always calling to_arg() functions).
- *
  * @param array $item
  *   The passed in item has the following keys:
  *   - access: (optional) Becomes TRUE if the item is accessible, FALSE
@@ -829,7 +309,7 @@ function _menu_link_translate(&$item) {
     }
     // For performance, don't localize a link the user can't access.
     if ($item['access']) {
-      _menu_item_localize($item, array(), TRUE);
+      _menu_item_localize($item);
     }
   }
 
@@ -841,62 +321,9 @@ function _menu_link_translate(&$item) {
   }
 }
 
-/**
- * Checks access to a menu item by mocking a request for a path.
- *
- * @param \Symfony\Component\Routing\Route $route
- *   Router for the given menu item.
- * @param string $href
- *   The menu path with '%' replaced by arguments.
- * @param array $map
- *   An array of path arguments; for example, array('node', '5').
- * @param \Symfony\Component\HttpFoundation\Request $request
- *   The current request object, used to find the current route.
- *
- * @return bool
- *   TRUE if the user has access or FALSE if the user should be presented
- *   with access denied.
- *
- */
-function menu_item_route_access(Route $route, $href, &$map, Request $request = NULL) {
-  if (!isset($request)) {
-    $request = RequestHelper::duplicate(\Drupal::request(), '/' . $href);
-    $request->attributes->set('_system_path', $href);
-  }
-  // Attempt to match this path to provide a fully built request to the
-  // access checker.
-  try {
-    $request->attributes->add(\Drupal::service('router')->matchRequest($request));
-  }
-  catch (ParamNotConvertedException $e) {
-    return FALSE;
-  }
-
-  // Populate the map with any matching values from the request.
-  $path_bits = explode('/', trim($route->getPath(), '/'));
-  foreach ($map as $index => $map_item) {
-    $matches = array();
-    // Search for placeholders wrapped by curly braces. For example, a path
-    // 'foo/{bar}/baz' would return 'bar'.
-    if (isset($path_bits[$index]) && preg_match('/{(?<placeholder>.*)}/', $path_bits[$index], $matches)) {
-      // If that placeholder is present on the request attributes, replace the
-      // placeholder in the map with the value.
-      if ($request->attributes->has($matches['placeholder'])) {
-        $map[$index] = $request->attributes->get($matches['placeholder']);
-      }
-    }
-  }
-
-  return \Drupal::service('access_manager')->check($route, $request, \Drupal::currentUser());
-}
-
 /**
  * Renders a menu tree based on the current path.
  *
- * The tree is expanded based on the current path and dynamic paths are also
- * changed according to the defined to_arg functions (for example the 'My
- * account' link is changed from user/% to a link with the current user's uid).
- *
  * @param $menu_name
  *   The name of the menu.
  *
@@ -1124,7 +551,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
 
   // Check if the active trail has been overridden for this menu tree.
   $active_path = menu_tree_get_path($menu_name);
-  // Load the router item corresponding to the current page.
+  // Load the request corresponding to the current page.
   $request = \Drupal::request();
   $system_path = NULL;
   if ($route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME)) {
@@ -2064,9 +1491,9 @@ function menu_link_get_preferred($path = NULL, $selected_menu = NULL) {
         foreach ($menu_names as $menu_name) {
           if (empty($preferred_links[$path][$menu_name]) && isset($candidates[$link_path][$menu_name])) {
             $candidate_item = $candidates[$link_path][$menu_name];
-            $map = explode('/', $path);
-            _menu_translate($candidate_item, $map);
+            $candidate_item['access'] = \Drupal::service('access_manager')->checkNamedRoute($candidate_item['route_name'], $candidate_item['route_parameters'], \Drupal::currentUser());
             if ($candidate_item['access']) {
+              _menu_item_localize($candidate_item);
               $preferred_links[$path][$menu_name] = $candidate_item;
               if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
                 // Store the most specific link.
@@ -2128,139 +1555,6 @@ function menu_reset_static_cache() {
   drupal_static_reset('menu_link_get_preferred');
 }
 
-/**
- * Populates the database tables used by various menu functions.
- *
- * This function will clear and populate the {menu_router} table, add entries
- * to {menu_links} for new router items, and then remove stale items from
- * {menu_links}.
- *
- * @return
- *   TRUE if the menu was rebuilt, FALSE if another thread was rebuilding
- *   in parallel and the current thread just waited for completion.
- */
-function menu_router_rebuild() {
-  if (!\Drupal::lock()->acquire(__FUNCTION__)) {
-    // Wait for another request that is already doing this work.
-    // We choose to block here since otherwise the router item may not
-    // be available during routing resulting in a 404.
-    \Drupal::lock()->wait(__FUNCTION__);
-    return FALSE;
-  }
-
-  $transaction = db_transaction();
-
-  try {
-    // Ensure the route based router is up to date.
-    \Drupal::service('router.builder')->rebuildIfNeeded();
-    list($menu) = menu_router_build(TRUE);
-    menu_link_rebuild_defaults();
-    // Clear the menu, page and block caches.
-    menu_cache_clear_all();
-    _menu_clear_page_cache();
-  }
-  catch (Exception $e) {
-    $transaction->rollback();
-    watchdog_exception('menu', $e);
-  }
-
-  \Drupal::lock()->release(__FUNCTION__);
-  return TRUE;
-}
-
-/**
- * Collects and alters the menu definitions.
- *
- * @param bool $save
- *   (optional) Save the new router to the database. Defaults to FALSE.
- */
-function menu_router_build($save = FALSE) {
-  // Ensure that all configuration used to build the menu items are loaded
-  // without overrides.
-  $old_state = \Drupal::configFactory()->getOverrideState();
-  \Drupal::configFactory()->setOverrideState(FALSE);
-  // We need to manually call each module so that we can know which module
-  // a given item came from.
-  $callbacks = array();
-  foreach (\Drupal::moduleHandler()->getImplementations('menu') as $module) {
-    $router_items = call_user_func($module . '_menu');
-    if (isset($router_items) && is_array($router_items)) {
-      foreach (array_keys($router_items) as $path) {
-        $router_items[$path]['module'] = $module;
-      }
-      $callbacks = array_merge($callbacks, $router_items);
-    }
-  }
-  // Alter the menu as defined in modules, keys are like user/%user.
-  \Drupal::moduleHandler()->alter('menu', $callbacks);
-  \Drupal::configFactory()->setOverrideState($old_state);
-  foreach ($callbacks as $path => $router_item) {
-    // If the menu item is a default local task and incorrectly references a
-    // route, remove it.
-    // @todo This may be removed later depending on the outcome of
-    // http://drupal.org/node/1889790
-    if (isset($router_item['type']) && $router_item['type'] == MENU_DEFAULT_LOCAL_TASK) {
-      unset($callbacks[$path]['route_name']);
-    }
-    // If the menu item references a route, normalize the route information
-    // into the old structure. Note that routes are keyed by name, not path,
-    // so the path of the route takes precedence.
-    if (isset($router_item['route_name'])) {
-      $router_item['page callback'] = 'USES_ROUTE';
-      $router_item['access callback'] = TRUE;
-      $new_path = _menu_router_translate_route($router_item['route_name']);
-
-      unset($callbacks[$path]);
-      $callbacks[$new_path] = $router_item;
-    }
-  }
-  list($menu, $masks) = _menu_router_build($callbacks, $save);
-  _menu_router_cache($menu);
-
-  return array($menu, $masks);
-}
-
-/**
- * Translates a route name to its router item path.
- *
- * @param string $route_name
- *   The route name to translate.
- *
- * @return string
- *   The translated path pattern from the route.
- */
-function _menu_router_translate_route($route_name) {
-  $outline = \Drupal::service('router.route_provider')
-    ->getRouteByName($route_name)
-    ->compile()
-    ->getPatternOutline();
-  return trim($outline, '/');
-}
-
-/**
- * Stores the menu router if we have it in memory.
- */
-function _menu_router_cache($new_menu = NULL) {
-  $menu = &drupal_static(__FUNCTION__);
-
-  if (isset($new_menu)) {
-    $menu = $new_menu;
-  }
-  return $menu;
-}
-
-/**
- * Gets the menu router.
- */
-function menu_get_router() {
-  // Check first if we have it in memory already.
-  $menu = _menu_router_cache();
-  if (empty($menu)) {
-    list($menu) = menu_router_build();
-  }
-  return $menu;
-}
-
 /**
  * Saves menu links recursively for menu_links_rebuild_defaults().
  */
@@ -2487,358 +1781,6 @@ function _menu_set_expanded_menus() {
   \Drupal::state()->set('menu_expanded', $names);
 }
 
-/**
- * Finds the router path which will serve this path.
- *
- * @param $link_path
- *  The path for we are looking up its router path.
- *
- * @return
- *  A path from $menu keys or empty if $link_path points to a nonexisting
- *  place.
- */
-function _menu_find_router_path($link_path) {
-  // $menu will only have data during a menu rebuild.
-  $menu = _menu_router_cache();
-
-  $router_path = $link_path;
-  $parts = explode('/', $link_path, MENU_MAX_PARTS);
-  $ancestors = menu_get_ancestors($parts);
-
-  if (empty($menu)) {
-    // Not during a menu rebuild, so look up in the database.
-    $router_path = (string) db_select('menu_router')
-      ->fields('menu_router', array('path'))
-      ->condition('path', $ancestors, 'IN')
-      ->orderBy('fit', 'DESC')
-      ->range(0, 1)
-      ->execute()->fetchField();
-  }
-  elseif (!isset($menu[$router_path])) {
-    // Add an empty router path as a fallback.
-    $ancestors[] = '';
-    foreach ($ancestors as $router_path) {
-      if (isset($menu[$router_path])) {
-        // Exit the loop leaving $router_path as the first match.
-        break;
-      }
-    }
-    // If we did not find the path, $router_path will be the empty string
-    // at the end of $ancestors.
-  }
-  return $router_path;
-}
-
-/**
- * Builds the router table based on the data from hook_menu().
- */
-function _menu_router_build($callbacks, $save = FALSE) {
-  // First pass: separate callbacks from paths, making paths ready for
-  // matching. Calculate fitness, and fill some default values.
-  $menu = array();
-  $masks = array();
-  $path_roots = array();
-  foreach ($callbacks as $path => $item) {
-    $load_functions = array();
-    $to_arg_functions = array();
-    $fit = 0;
-    $move = FALSE;
-
-    $parts = explode('/', $path, MENU_MAX_PARTS);
-    $path_roots[$parts[0]] = $parts[0];
-    $number_parts = count($parts);
-    // We store the highest index of parts here to save some work in the fit
-    // calculation loop.
-    $slashes = $number_parts - 1;
-    // Extract load and to_arg functions.
-    foreach ($parts as $k => $part) {
-      $match = FALSE;
-      // Look for wildcards in the form allowed to be used in PHP functions,
-      // because we are using these to construct the load function names.
-      if (preg_match('/^%(|' . DRUPAL_PHP_FUNCTION_PATTERN . ')$/', $part, $matches)) {
-        if (empty($matches[1])) {
-          $match = TRUE;
-          $load_functions[$k] = NULL;
-        }
-        else {
-          if (function_exists($matches[1] . '_to_arg')) {
-            $to_arg_functions[$k] = $matches[1] . '_to_arg';
-            $load_functions[$k] = NULL;
-            $match = TRUE;
-          }
-          if (function_exists($matches[1] . '_load')) {
-            $function = $matches[1] . '_load';
-            // Create an array of arguments that will be passed to the _load
-            // function when this menu path is checked, if 'load arguments'
-            // exists.
-            $load_functions[$k] = isset($item['load arguments']) ? array($function => $item['load arguments']) : $function;
-            $match = TRUE;
-          }
-        }
-      }
-      if ($match) {
-        $parts[$k] = '%';
-      }
-      else {
-        $fit |=  1 << ($slashes - $k);
-      }
-    }
-    if ($fit) {
-      $move = TRUE;
-    }
-    else {
-      // If there is no %, it fits maximally.
-      $fit = (1 << $number_parts) - 1;
-    }
-    $masks[$fit] = 1;
-    $item['_load_functions'] = $load_functions;
-    $item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions);
-    $item += array(
-      'title' => '',
-      'type' => MENU_NORMAL_ITEM,
-      'module' => '',
-      '_number_parts' => $number_parts,
-      '_parts' => $parts,
-      '_fit' => $fit,
-    );
-    $item += array(
-      // Default MENU_DEFAULT_LOCAL_TASKs to a weight of -10, so they appear as
-      // first tab by default.
-      'weight' => ($item['type'] & MENU_DEFAULT_LOCAL_TASK) == MENU_DEFAULT_LOCAL_TASK ? -10 : 0,
-      '_visible' => (bool) ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
-      '_tab' => (bool) ($item['type'] & MENU_IS_LOCAL_TASK),
-    );
-    if ($move) {
-      $new_path = implode('/', $item['_parts']);
-      $menu[$new_path] = $item;
-      $sort[$new_path] = $number_parts;
-    }
-    else {
-      $menu[$path] = $item;
-      $sort[$path] = $number_parts;
-    }
-  }
-  array_multisort($sort, SORT_NUMERIC, $menu);
-  // Apply inheritance rules.
-  foreach ($menu as $path => $v) {
-    $item = &$menu[$path];
-    if (!$item['_tab']) {
-      // Non-tab items.
-      $item['tab_parent'] = '';
-      $item['tab_root'] = $path;
-    }
-    // If not specified, assign the default tab type for local tasks.
-    elseif (!isset($item['context'])) {
-      $item['context'] = MENU_CONTEXT_PAGE;
-    }
-    for ($i = $item['_number_parts'] - 1; $i; $i--) {
-      $parent_path = implode('/', array_slice($item['_parts'], 0, $i));
-      if (isset($menu[$parent_path])) {
-
-        $parent = &$menu[$parent_path];
-
-        // If we have no menu name, try to inherit it from parent items.
-        if (!isset($item['menu_name'])) {
-          // If the parent item of this item does not define a menu name (and no
-          // previous iteration assigned one already), try to find the menu name
-          // of the parent item in the currently stored menu links.
-          if (!isset($parent['menu_name'])) {
-            $menu_name = db_query("SELECT menu_name FROM {menu_links} WHERE link_path = :link_path AND module = 'system'", array(':link_path' => $parent_path))->fetchField();
-            if ($menu_name) {
-              $parent['menu_name'] = $menu_name;
-            }
-          }
-          // If the parent item defines a menu name, inherit it.
-          if (!empty($parent['menu_name'])) {
-            $item['menu_name'] = $parent['menu_name'];
-          }
-        }
-        if (!isset($item['tab_parent'])) {
-          // Parent stores the parent of the path.
-          $item['tab_parent'] = $parent_path;
-        }
-        if (!isset($item['tab_root']) && !$parent['_tab']) {
-          $item['tab_root'] = $parent_path;
-        }
-        // If an access callback is not found for a default local task we use
-        // the callback from the parent, since we expect them to be identical.
-        // In all other cases, the access parameters must be specified.
-        if (($item['type'] == MENU_DEFAULT_LOCAL_TASK) && !isset($item['access callback']) && isset($parent['access callback'])) {
-          $item['access callback'] = $parent['access callback'];
-          if (!isset($item['access arguments']) && isset($parent['access arguments'])) {
-            $item['access arguments'] = $parent['access arguments'];
-          }
-        }
-        // Same for page callbacks.
-        if (!isset($item['page callback']) && isset($parent['page callback'])) {
-          $item['page callback'] = $parent['page callback'];
-          if (!isset($item['page arguments']) && isset($parent['page arguments'])) {
-            $item['page arguments'] = $parent['page arguments'];
-          }
-          if (!isset($item['file path']) && isset($parent['file path'])) {
-            $item['file path'] = $parent['file path'];
-          }
-          if (!isset($item['file']) && isset($parent['file'])) {
-            $item['file'] = $parent['file'];
-            if (empty($item['file path']) && isset($item['module']) && isset($parent['module']) && $item['module'] != $parent['module']) {
-              $item['file path'] = drupal_get_path('module', $parent['module']);
-            }
-          }
-        }
-        // Same for load arguments: if a loader doesn't have any explict
-        // arguments, try to find arguments in the parent.
-        if (!isset($item['load arguments'])) {
-          foreach ($item['_load_functions'] as $k => $function) {
-            // This loader doesn't have any explict arguments...
-            if (!is_array($function)) {
-              // ... check the parent for a loader at the same position
-              // using the same function name and defining arguments...
-              if (isset($parent['_load_functions'][$k]) && is_array($parent['_load_functions'][$k]) && key($parent['_load_functions'][$k]) === $function) {
-                // ... and inherit the arguments on the child.
-                $item['_load_functions'][$k] = $parent['_load_functions'][$k];
-              }
-            }
-          }
-        }
-      }
-    }
-    if (!isset($item['access callback']) && isset($item['access arguments'])) {
-      // Default callback.
-      $item['access callback'] = 'user_access';
-    }
-    if (!isset($item['access callback']) || empty($item['page callback'])) {
-      $item['access callback'] = 0;
-    }
-    if (is_bool($item['access callback'])) {
-      $item['access callback'] = intval($item['access callback']);
-    }
-
-    $item['load_functions'] = empty($item['_load_functions']) ? '' : serialize($item['_load_functions']);
-    $item += array(
-      'access arguments' => array(),
-      'access callback' => '',
-      'page arguments' => array(),
-      'page callback' => '',
-      'title arguments' => array(),
-      'title callback' => 't',
-      'description' => '',
-      'description arguments' => array(),
-      'description callback' => 't',
-      'position' => '',
-      'context' => 0,
-      'tab_parent' => '',
-      'tab_root' => $path,
-      'path' => $path,
-      'file' => '',
-      'file path' => '',
-      'include file' => '',
-      'route_name' => '',
-    );
-
-    // Calculate out the file to be included for each callback, if any.
-    if ($item['file']) {
-      $file_path = $item['file path'] ? $item['file path'] : drupal_get_path('module', $item['module']);
-      $item['include file'] = $file_path . '/' . $item['file'];
-    }
-  }
-
-  // Sort the masks so they are in order of descending fit.
-  $masks = array_keys($masks);
-  rsort($masks);
-
-  if ($save) {
-    $path_roots = array_values($path_roots);
-    // Update the path roots variable and reset the path alias whitelist cache
-    // if the list has changed.
-    if ($path_roots != \Drupal::state()->get('menu_path_roots')) {
-      \Drupal::state()->set('menu_path_roots', array_values($path_roots));
-      \Drupal::service('path.alias_manager')->cacheClear();
-    }
-    _menu_router_save($menu, $masks);
-  }
-
-  return array($menu, $masks);
-}
-
-/**
- * Saves data from menu_router_build() to the router table.
- */
-function _menu_router_save($menu, $masks) {
-  // Delete the existing router since we have some data to replace it.
-  db_truncate('menu_router')->execute();
-
-  // Prepare insert object.
-  $insert = db_insert('menu_router')
-    ->fields(array(
-      'path',
-      'load_functions',
-      'to_arg_functions',
-      'access_callback',
-      'access_arguments',
-      'page_callback',
-      'page_arguments',
-      'fit',
-      'number_parts',
-      'context',
-      'tab_parent',
-      'tab_root',
-      'title',
-      'title_callback',
-      'title_arguments',
-      'type',
-      'description',
-      'description_callback',
-      'description_arguments',
-      'position',
-      'weight',
-      'include_file',
-      'route_name',
-    ));
-
-  $num_records = 0;
-
-  foreach ($menu as $item) {
-    // Fill in insert object values.
-    $insert->values(array(
-      'path' => $item['path'],
-      'load_functions' => $item['load_functions'],
-      'to_arg_functions' => $item['to_arg_functions'],
-      'access_callback' => $item['access callback'],
-      'access_arguments' => serialize($item['access arguments']),
-      'page_callback' => $item['page callback'],
-      'page_arguments' => serialize($item['page arguments']),
-      'fit' => $item['_fit'],
-      'number_parts' => $item['_number_parts'],
-      'context' => $item['context'],
-      'tab_parent' => $item['tab_parent'],
-      'tab_root' => $item['tab_root'],
-      'title' => $item['title'],
-      'title_callback' => $item['title callback'],
-      'title_arguments' => ($item['title arguments'] ? serialize($item['title arguments']) : ''),
-      'type' => $item['type'],
-      'description' => $item['description'],
-      'description_callback' => $item['description callback'],
-      'description_arguments' => ($item['description arguments'] ? serialize($item['description arguments']) : ''),
-      'position' => $item['position'],
-      'weight' => $item['weight'],
-      'include_file' => $item['include file'],
-      'route_name' => $item['route_name'],
-    ));
-
-    // Execute in batches to avoid the memory overhead of all of those records
-    // in the query object.
-    if (++$num_records == 20) {
-      $insert->execute();
-      $num_records = 0;
-    }
-  }
-  // Insert any remaining records.
-  $insert->execute();
-  // Store the masks.
-  \Drupal::state()->set('menu.masks', $masks);
-
-  return $menu;
-}
 
 /**
  * Checks whether the site is in maintenance mode.
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 912610d9886f9ece4d38e970d608fc84c08d55f9..3193d0ea3ddfaad661d662513f5d83e891eabc58 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -5,8 +5,9 @@
  * Functions to handle paths in Drupal.
  */
 
+use Drupal\Component\Utility\Url;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\Routing\RequestHelper;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Check if the current page is the front page.
@@ -183,57 +184,42 @@ function path_get_admin_paths() {
 /**
  * Checks a path exists and the current user has access to it.
  *
- * @param $path
+ * @param string $path
  *   The path to check.
- * @param $dynamic_allowed
- *   Whether paths with menu wildcards (like user/%) should be allowed.
  *
- * @return
+ * @return bool
  *   TRUE if it is a valid path AND the current user has access permission,
  *   FALSE otherwise.
  */
-function drupal_valid_path($path, $dynamic_allowed = FALSE) {
-  global $menu_admin;
-  // We indicate that a menu administrator is running the menu access check.
-  $menu_admin = TRUE;
-  /** @var $route_provider \Drupal\Core\Routing\RouteProviderInterface */
-  $route_provider = \Drupal::service('router.route_provider');
-
-  if ($dynamic_allowed && preg_match('/\/\%/', $path)) {
-    $router_path = '/' . str_replace('%', '{}', $path);
-  }
-  else {
-    $router_path = $path;
+function drupal_valid_path($path) {
+  // External URLs and the front page are always valid.
+  if ($path == '<front>' || Url::isExternal($path)) {
+    return TRUE;
   }
 
-  if ($path == '<front>' || url_is_external($path)) {
-    $item = array('access' => TRUE);
-  }
-  elseif (($collection = $route_provider->getRoutesByPattern('/' . $router_path)) && $collection->count() > 0) {
-    $routes = $collection->all();
-    $route_name = key($routes);
+  // Check the routing system.
+  $collection = \Drupal::service('router.route_provider')->getRoutesByPattern('/' . $path);
+  if ($collection->count() == 0) {
+    return FALSE;
   }
-  elseif ($dynamic_allowed && preg_match('/\/\%/', $path)) {
-    // Path is dynamic (ie 'user/%'), so check directly against menu_router table.
-    if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) {
-      $item['link_path']  = $item['path'];
-      $item['link_title'] = $item['title'];
-      $item['external']   = FALSE;
-      $item['options'] = '';
-      _menu_link_translate($item);
-      $route_name = $item['route_name'];
-    }
+
+  $request = RequestHelper::duplicate(\Drupal::request(), '/' . $path);
+  $request->attributes->set('_system_path', $path);
+
+  // We indicate that a menu administrator is running the menu access check.
+  $request->attributes->set('_menu_admin', TRUE);
+
+  // Attempt to match this path to provide a fully built request to the
+  // access checker.
+  try {
+    $request->attributes->add(\Drupal::service('router')->matchRequest($request));
   }
-  // Check the new routing system.
-  if (!empty($route_name)) {
-    $map = array();
-    $route = \Drupal::service('router.route_provider')->getRouteByName($route_name);
-    $request = RequestHelper::duplicate(\Drupal::request(), '/' . $path);
-    $request->attributes->set('_system_path', $path);
-    $request->attributes->set('_menu_admin', TRUE);
-
-    $item['access'] = menu_item_route_access($route, $path, $map, $request);
+  catch (ParamNotConvertedException $e) {
+    return FALSE;
   }
-  $menu_admin = FALSE;
-  return !empty($item['access']);
+
+  // Consult the accsss manager.
+  $routes = $collection->all();
+  $route = reset($routes);
+  return \Drupal::service('access_manager')->check($route, $request, \Drupal::currentUser());
 }
diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
index d432656bf05acbb03d4b48006cef56c43d0dfe4a..98bf05c5422a7dd55df4159c4775d3c93b54c5e4 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\EventSubscriber;
 
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\Core\Routing\RouteBuilderInterface;
 use Drupal\Core\Routing\RoutingEvents;
 use Symfony\Component\EventDispatcher\Event;
@@ -16,7 +17,7 @@
 use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
- * Rebuilds the router and menu_router if necessary.
+ * Rebuilds the default menu links and runs menu-specific code if necessary.
  */
 class RouterRebuildSubscriber implements EventSubscriberInterface {
 
@@ -25,14 +26,22 @@ class RouterRebuildSubscriber implements EventSubscriberInterface {
    */
   protected $routeBuilder;
 
+  /**
+   * @var \Drupal\Core\Lock\LockBackendInterface
+   */
+  protected $lock;
+
   /**
    * Constructs the RouterRebuildSubscriber object.
    *
    * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
    *   The route builder.
+   * @param \Drupal\Core\Lock\LockBackendInterface $lock
+   *   The lock backend.
    */
-  public function __construct(RouteBuilderInterface $route_builder) {
+  public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock) {
     $this->routeBuilder = $route_builder;
+    $this->lock = $lock;
   }
 
   /**
@@ -46,16 +55,44 @@ public function onKernelTerminate(PostResponseEvent $event) {
   }
 
   /**
-   * Rebuilds the menu_router and deletes the local_task cache tag.
+   * Rebuilds the menu links and deletes the local_task cache tag.
    *
    * @param \Symfony\Component\EventDispatcher\Event $event
    *   The event object.
    */
   public function onRouterRebuild(Event $event) {
-    menu_router_rebuild();
+    $this->menuLinksRebuild();
     Cache::deleteTags(array('local_task' => 1));
   }
 
+  /**
+   * Perform menu-specific rebuilding.
+   */
+  protected function menuLinksRebuild() {
+    if ($this->lock->acquire(__FUNCTION__)) {
+      $transaction = db_transaction();
+      try {
+        // Ensure the menu links are up to date.
+        menu_link_rebuild_defaults();
+        // Clear the menu, page and block caches.
+        menu_cache_clear_all();
+        _menu_clear_page_cache();
+      }
+      catch (\Exception $e) {
+        $transaction->rollback();
+        watchdog_exception('menu', $e);
+      }
+
+      $this->lock->release(__FUNCTION__);
+    }
+    else {
+      // Wait for another request that is already doing this work.
+      // We choose to block here since otherwise the router item may not
+      // be available during routing resulting in a 404.
+      $this->lock->wait(__FUNCTION__);
+    }
+  }
+
   /**
    * Registers the methods in this class that should be listeners.
    *
diff --git a/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php b/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
index 79fe59f62053b40e2e7ead65eb6952f776d855b3..282b89102dcd2fe077fa9ad08b6bbcd071c57623 100644
--- a/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
+++ b/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
@@ -70,7 +70,7 @@ public function cleanup(Request $request) {}
    */
   public function handleException(GetResponseForExceptionEvent $event) {
     $exception = $event->getException();
-    if (user_is_anonymous() && $exception instanceof AccessDeniedHttpException) {
+    if ($GLOBALS['user']->isAnonymous() && $exception instanceof AccessDeniedHttpException) {
       if (!$this->applies($event->getRequest())) {
         $site_name = $this->configFactory->get('system.site')->get('name');
         global $base_url;
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
index 7593adb461b80355d4c3cb821955ea470ddba79a..82cb852056626367740e846678ef91efb3c593f5 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockTypeTest.php
@@ -158,7 +158,7 @@ public function testsCustomBlockAddTypes() {
     foreach ($themes as $default_theme) {
       // Change the default theme.
       $theme_settings->set('default', $default_theme)->save();
-      menu_router_rebuild();
+      \Drupal::service('router.builder')->rebuild();
 
       // For each enabled theme, go to its block page and test the redirects.
       $themes = array('bartik', 'stark', 'seven');
diff --git a/core/modules/book/lib/Drupal/book/BookManager.php b/core/modules/book/lib/Drupal/book/BookManager.php
index 8edd4d70da4141583a00f5efb952d2574db3a919..0c8dfd42ad5f274d2a08d164a5d30590d68a6863 100644
--- a/core/modules/book/lib/Drupal/book/BookManager.php
+++ b/core/modules/book/lib/Drupal/book/BookManager.php
@@ -865,7 +865,7 @@ protected function _menu_tree_check_access(&$tree) {
    * Provides menu link access control, translation, and argument handling.
    *
    * This function is similar to _menu_translate(), but it also does
-   * link-specific preparation (such as always calling to_arg() functions).
+   * link-specific preparation.
    *
    * @param $item
    *   A menu link.
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index fe9079990f75a38d6b0a8afd990963786646cbee..6a96f4de7e01d70b417d96d6552146e663c26efc 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -228,7 +228,7 @@ function contact_form_user_form_alter(&$form, &$form_state) {
     '#weight' => 5,
   );
   $account = $form_state['controller']->getEntity();
-  $account_data = !user_is_anonymous() ? \Drupal::service('user.data')->get('contact', $account->id(), 'enabled') : NULL;
+  $account_data = !\Drupal::currentUser()->isAnonymous() ? \Drupal::service('user.data')->get('contact', $account->id(), 'enabled') : NULL;
   $form['contact']['contact'] = array(
     '#type' => 'checkbox',
     '#title' => t('Personal contact form'),
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 8c65f1e9f37c6bdffe34f86765ff91dbb8814a23..a866a282bbd5f1bd64c2d9ca119ab7f8f9c2d042 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -181,62 +181,6 @@ function content_translation_entity_operation_alter(array &$operations, \Drupal\
   }
 }
 
-/**
- * Implements hook_menu().
- *
- * @todo Split this into route definition and menu link definition. See
- *   https://drupal.org/node/1987882 and https://drupal.org/node/2047633.
- */
-function content_translation_menu() {
-  $items = array();
-
-  // Create tabs for all possible entity types.
-  foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
-    // Provide the translation UI only for enabled types.
-    if (content_translation_enabled($entity_type_id)) {
-      $path = _content_translation_link_to_router_path($entity_type_id, $entity_type->getLinkTemplate('canonical'));
-      $entity_position = count(explode('/', $path)) - 1;
-      $keys = array_flip(array('load_arguments'));
-      $translation = $entity_type->get('translation');
-      $menu_info = array_intersect_key($translation['content_translation'], $keys) + array('file' => 'content_translation.pages.inc');
-      $item = array();
-
-      // Plugin annotations cannot contain spaces, thus we need to restore them
-      // from underscores.
-      foreach ($menu_info as $key => $value) {
-        $item[str_replace('_', ' ', $key)] = $value;
-      }
-
-      // Add translation callback.
-      // @todo Add the access callback instead of replacing it as soon as the
-      // routing system supports multiple callbacks.
-      $language_position = $entity_position + 3;
-      $args = array($entity_position, $language_position, $language_position + 1);
-      $items["$path/translations/add/%language/%language"] = array(
-        'title' => 'Add',
-        'route_name' => "content_translation.translation_add_$entity_type_id",
-        'weight' => 1,
-      );
-
-      // Edit translation callback.
-      $args = array($entity_position, $language_position);
-      $items["$path/translations/edit/%language"] = array(
-        'title' => 'Edit',
-        'route_name' => "content_translation.translation_edit_$entity_type_id",
-        'weight' => 1,
-      );
-
-      // Delete translation callback.
-      $items["$path/translations/delete/%language"] = array(
-        'title' => 'Delete',
-        'route_name' => "content_translation.delete_$entity_type_id",
-      ) + $item;
-    }
-  }
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_alter().
  *
@@ -973,7 +917,7 @@ function content_translation_language_configuration_element_submit(array $form,
   if (content_translation_enabled($context['entity_type'], $context['bundle']) != $enabled) {
     content_translation_set_config($context['entity_type'], $context['bundle'], 'enabled', $enabled);
     entity_info_cache_clear();
-    menu_router_rebuild();
+    \Drupal::service('router.builder')->setRebuildNeeded();
   }
 }
 
@@ -1041,5 +985,5 @@ function content_translation_save_settings($settings) {
 
   // Ensure entity and menu router information are correctly rebuilt.
   entity_info_cache_clear();
-  menu_router_rebuild();
+  \Drupal::service('router.builder')->setRebuildNeeded();
 }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
index c753114dcab4486b6d06b9eb23e90894f02715c8..09afe8ca762fb6de6988f9abdfe22dc0ba0a763a 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
@@ -166,7 +166,7 @@ protected function enableTranslation() {
     content_translation_set_config($this->entityTypeId, $this->bundle, 'enabled', TRUE);
     drupal_static_reset();
     entity_info_cache_clear();
-    menu_router_rebuild();
+    \Drupal::service('router.builder')->rebuild();
   }
 
   /**
diff --git a/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php b/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php
index 57e45c1fa23e73d9e51cb03edc93a8e09c7c0a00..709c71bb041f7f0d7cc619006084227980602c0b 100644
--- a/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php
+++ b/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php
@@ -104,7 +104,7 @@ public function submit(array $form, array &$form_state) {
       return;
     }
 
-    // Reset all the menu links defined by the system via hook_menu().
+    // Reset all the menu links defined by the system via hook_menu_link_defaults().
     // @todo Convert this to an EFQ.
     $result = $this->connection->query("SELECT mlid FROM {menu_links} WHERE menu_name = :menu AND module = 'system' ORDER BY depth ASC", array(':menu' => $this->entity->id()), array('fetch' => \PDO::FETCH_ASSOC))->fetchCol();
     $menu_links = $this->storageController->loadMultiple($result);
diff --git a/core/modules/menu/lib/Drupal/menu/MenuFormController.php b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
index c054484311b8f324adf742ef7b0fee0273aa3410..d6720a7a408271986d1354073afadf5b21dbc667 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
@@ -235,8 +235,6 @@ public function save(array $form, array &$form_state) {
    * their form submit handler.
    */
   protected function buildOverviewForm(array &$form, array &$form_state) {
-    global $menu_admin;
-
     // Ensure that menu_overview_form_submit() knows the parents of this form
     // section.
     $form['#tree'] = TRUE;
@@ -261,10 +259,11 @@ protected function buildOverviewForm(array &$form, array &$form_state) {
     $tree = menu_tree_data($links);
     $node_links = array();
     menu_tree_collect_node_links($tree, $node_links);
+
     // We indicate that a menu administrator is running the menu access check.
-    $menu_admin = TRUE;
+    $this->getRequest()->attributes->set('_menu_admin', TRUE);
     menu_tree_check_access($tree, $node_links);
-    $menu_admin = FALSE;
+    $this->getRequest()->attributes->set('_menu_admin', FALSE);
 
     $form = array_merge($form, $this->buildOverviewTreeForm($tree, $delta));
     $form['#empty_text'] = t('There are no menu links yet. <a href="@link">Add link</a>.', array('@link' => url('admin/structure/menu/manage/' . $this->entity->id() .'/add')));
diff --git a/core/modules/menu/menu.install b/core/modules/menu/menu.install
index c1615921aec8a567c4eea9af5bb864d50c078393..037fc62531174982df4780c8463de9c69ca094a0 100644
--- a/core/modules/menu/menu.install
+++ b/core/modules/menu/menu.install
@@ -17,7 +17,6 @@ function menu_install() {
   // \Drupal\Core\Extension\ModuleHandler::install().
   // @see https://drupal.org/node/2181151
   \Drupal::service('router.builder')->rebuild();
-  menu_router_rebuild();
   if (\Drupal::moduleHandler()->moduleExists('node')) {
     $node_types = array_keys(node_type_get_names());
     foreach ($node_types as $type_id) {
@@ -33,5 +32,5 @@ function menu_install() {
  * Implements hook_uninstall().
  */
 function menu_uninstall() {
-  menu_router_rebuild();
+  \Drupal::service('router.builder')->setRebuildNeeded();
 }
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
index 10d998e5c27fc2b29a8670206cb716b92b150dbd..ee9d0b8584c6f57fec118ded1f4da44f2ad3ae11 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
@@ -7,15 +7,9 @@
 
 namespace Drupal\menu_link;
 
-use Drupal\Component\Uuid\UuidInterface;
 use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageException;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\field\FieldInfo;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Cmf\Component\Routing\RouteProviderInterface;
 
 /**
  * Controller class for menu links.
@@ -25,13 +19,6 @@
  */
 class MenuLinkStorageController extends DatabaseStorageController implements MenuLinkStorageControllerInterface {
 
-  /**
-   * Contains all {menu_router} fields without weight.
-   *
-   * @var array
-   */
-  protected static $routerItemFields;
-
   /**
    * Indicates whether the delete operation should re-parent children items.
    *
@@ -39,35 +26,6 @@ class MenuLinkStorageController extends DatabaseStorageController implements Men
    */
   protected $preventReparenting = FALSE;
 
-  /**
-   * The route provider service.
-   *
-   * @var \Symfony\Cmf\Component\Routing\RouteProviderInterface
-   */
-  protected $routeProvider;
-
-  /**
-   * Overrides DatabaseStorageController::__construct().
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type definition.
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection to be used.
-   * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
-   *   The UUID Service.
-   * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $route_provider
-   *   The route provider service.
-   */
-  public function __construct(EntityTypeInterface $entity_type, Connection $database, UuidInterface $uuid_service, RouteProviderInterface $route_provider) {
-    parent::__construct($entity_type, $database, $uuid_service);
-
-    $this->routeProvider = $route_provider;
-
-    if (empty(static::$routerItemFields)) {
-      static::$routerItemFields = array_diff(drupal_schema_fields_sql('menu_router'), array('weight'));
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -80,29 +38,6 @@ public function create(array $values = array()) {
     return parent::create($values);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
-    return new static(
-      $entity_type,
-      $container->get('database'),
-      $container->get('uuid'),
-      $container->get('router.route_provider')
-    );
-  }
-
-  /**
-   * Overrides DatabaseStorageController::buildQuery().
-   */
-  protected function buildQuery($ids, $revision_id = FALSE) {
-    $query = parent::buildQuery($ids, $revision_id);
-    // Specify additional fields from the {menu_router} table.
-    $query->leftJoin('menu_router', 'm', 'base.link_path = m.path');
-    $query->fields('m', static::$routerItemFields);
-    return $query;
-  }
-
   /**
    * Overrides DatabaseStorageController::save().
    */
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
index f084a9c91a919908c9ba3320a5dd4ddf9d5092e7..5468547eb9da207c55a24bdb333c3d4ab07b9db4 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
@@ -55,7 +55,7 @@ class OptionsFieldUnitTestBase extends FieldUnitTestBase {
    */
   public function setUp() {
     parent::setUp();
-    $this->installSchema('system', array('router', 'menu_router'));
+    $this->installSchema('system', array('router'));
 
     $this->fieldDefinition = array(
       'name' => $this->fieldName,
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index e62405709ff02a6f6baa69739c97719ee0e8d503..a442dd076611068e039369be831b3fd4d8dc2187 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -324,7 +324,7 @@ protected function drupalCreateContentType(array $values = array()) {
     );
     $type = entity_create('node_type', $values);
     $status = $type->save();
-    menu_router_rebuild();
+    \Drupal::service('router.builder')->rebuild();
 
     $this->assertEqual($status, SAVED_NEW, String::format('Created content type %type.', array('%type' => $type->id())));
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
index 418c451430beb09322264737062f4ebc8352e914..93bb4466c6f71d332b460b2bcf6454a65a03700a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
@@ -49,7 +49,7 @@ function setUp() {
   public function testMenuRouterRebuildContext() {
     // Enter a language context before rebuilding the menu router tables.
     \Drupal::configFactory()->setLanguage(language_load('nl'));
-    menu_router_rebuild();
+    \Drupal::service('router.builder')->rebuild();
 
     // Check that the language context was not used for building the menu item.
     $menu_items = \Drupal::entityManager()->getStorageController('menu_link')->loadByProperties(array('route_name' => 'menu_test.context'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
index f631d6fbbaf4fb2ac44562888523a7fc2b4ea373..72fe06af24bb96d3fa2dc4247c4d5f9f5736de41 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
@@ -10,7 +10,7 @@
 use Drupal\simpletest\WebTestBase;
 
 /**
- * Tests menu router and hook_menu() functionality.
+ * Tests menu router and hook_menu_link_defaults() functionality.
  */
 class MenuRouterTest extends WebTestBase {
 
@@ -45,7 +45,7 @@ class MenuRouterTest extends WebTestBase {
   public static function getInfo() {
     return array(
       'name' => 'Menu router',
-      'description' => 'Tests menu router and hook_menu() functionality.',
+      'description' => 'Tests menu router and hook_menu_link_defaults() functionality.',
       'group' => 'Menu',
     );
   }
@@ -69,7 +69,6 @@ public function testMenuIntegration() {
     $this->doTestMenuLinkMaintain();
     $this->doTestMenuLinkOptions();
     $this->doTestMenuItemHooks();
-    $this->doTestDescriptionMenuItems();
     $this->doTestHookMenuIntegration();
     $this->doTestExoticPath();
   }
@@ -119,7 +118,6 @@ protected function doTestDescriptionMenuItems() {
     // Verify that the menu router item title is output as page title.
     $this->drupalGet('menu_callback_description');
     $this->assertText(t('Menu item description text'));
-    $this->assertRaw(check_plain('<strong>Menu item description arguments</strong>'));
   }
 
   /**
@@ -169,7 +167,7 @@ protected function doTestMenuLinkMaintain() {
   }
 
   /**
-   * Tests for menu_name parameter for hook_menu().
+   * Tests for menu_name parameter for hook_menu_link_defaults().
    */
   protected function doTestMenuName() {
     $admin_user = $this->drupalCreateUser(array('administer site configuration'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/RebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/RebuildTest.php
deleted file mode 100644
index e02c9c4f23d45b5e6412d295dd6d819ebfdc9f1f..0000000000000000000000000000000000000000
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/RebuildTest.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Menu\RebuildTest.
- */
-
-namespace Drupal\system\Tests\Menu;
-
-use Drupal\Core\Routing\RouteBuilderInterface;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests rebuilding the router.
- */
-class RebuildTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Menu rebuild test',
-      'description' => 'Test rebuilding of menu.',
-      'group' => 'Menu',
-    );
-  }
-
-  /**
-   * Tests that set a router rebuild needed works.
-   */
-  function testMenuRebuild() {
-    // Check if 'admin' path exists.
-    $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
-    $this->assertEqual($admin_exists, 'admin', "The path 'admin/' exists prior to deleting.");
-
-    // Delete the path item 'admin', and test that the path doesn't exist in the database.
-    db_delete('menu_router')
-      ->condition('path', 'admin')
-      ->execute();
-    $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
-    $this->assertFalse($admin_exists, "The path 'admin/' has been deleted and doesn't exist in the database.");
-
-    // Now we set the router to be rebuilt. After the rebuild 'admin' should exist.
-    \Drupal::service('router.builder')->setRebuildNeeded();
-
-    // The request should trigger the rebuild.
-    $this->drupalGet('<front>');
-    $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
-    $this->assertEqual($admin_exists, 'admin', "The menu has been rebuilt, the path 'admin' now exists again.");
-  }
-
-}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeAccessTest.php
index df10877630d34b3154db851ff6fb14c12e45a33b..974208f5d0dcc103c578a3468113f45d43a7f504 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeAccessTest.php
@@ -14,7 +14,7 @@
 use Symfony\Component\Routing\RouteCollection;
 
 /**
- * Tests the access check for menu tree using both hook_menu() and route items.
+ * Tests the access check for menu tree using both menu links and route items.
  */
 
 class TreeAccessTest extends DrupalUnitTestBase {
@@ -43,7 +43,7 @@ class TreeAccessTest extends DrupalUnitTestBase {
   public static function getInfo() {
     return array(
       'name' => 'Menu tree access',
-      'description' => 'Tests the access check for menu tree using both hook_menu() and route items.',
+      'description' => 'Tests the access check for menu tree using both menu links and route items.',
       'group' => 'Menu',
     );
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
index d6927181657c947ada248afd3ef218c36a0998f8..bc80cb584f244d479758274416859d86ca3d2d92 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
@@ -32,7 +32,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('router', 'menu_router'));
+    $this->installSchema('system', array('router'));
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php
index 060303a525006ef582aa4d356b1d39f22d888887..e33156d917c4c5b650c6c8f7a15f1f8062998e05 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterPermissionTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Routing;
 
+use Drupal\Core\Routing\RequestHelper;
 use Drupal\simpletest\WebTestBase;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
 
@@ -37,17 +38,6 @@ public function testPermissionAccess() {
     $path = 'router_test/test7';
     $this->drupalGet($path);
     $this->assertResponse(403, "Access denied for a route where we don't have a permission");
-    // An invalid path should throw an exception.
-    $map = array();
-    $route = \Drupal::service('router.route_provider')->getRouteByName('router_test.7');
-    try {
-      menu_item_route_access($route, $path . 'invalid', $map);
-      $exception = FALSE;
-    }
-    catch (ResourceNotFoundException $e) {
-      $exception = TRUE;
-    }
-    $this->assertTrue($exception, 'A ResourceNotFoundException was thrown while checking access for an invalid route.');
 
     $this->drupalGet('router_test/test8');
     $this->assertResponse(403, 'Access denied by default if no access specified');
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php b/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php
index 900a4fa5334294098f1180136506994f2a613f5d..44cccb2ca7ea5a3a50db5d6037505bc2cacad556 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php
@@ -53,12 +53,10 @@ function testAdminPages() {
 
     // Verify that all visible, top-level administration links are listed on
     // the main administration page.
-    foreach (menu_get_router() as $path => $item) {
-      if (strpos($path, 'admin/') === 0 && ($item['type'] & MENU_VISIBLE_IN_TREE) && $item['_number_parts'] == 2) {
-        $this->assertLink($item['title']);
-        $this->assertLinkByHref($path);
-        $this->assertText($item['description']);
-      }
+    foreach ($this->getTopLevelMenuLinks() as $item) {
+      $this->assertLink($item['title']);
+      $this->assertLinkByHref($item['link_path']);
+      $this->assertText($item['localized_options']['attributes']['title']);
     }
 
     // For each administrative listing page on which the Locale module appears,
@@ -110,6 +108,31 @@ function testAdminPages() {
     }
   }
 
+  /**
+   * Returns all top level menu links.
+   *
+   * @return \Drupal\menu_link\MenuLinkInterface[]
+   */
+  protected function getTopLevelMenuLinks() {
+    $route_provider = \Drupal::service('router.route_provider');
+    $routes = array();
+    foreach ($route_provider->getAllRoutes() as $key => $value) {
+      $path = $value->getPath();
+      if (strpos($path, '/admin/') === 0 && count(explode('/', $path)) == 3) {
+        $routes[$key] = $key;
+      }
+    }
+    $menu_link_ids = \Drupal::entityQuery('menu_link')
+      ->condition('route_name', $routes)
+      ->execute();
+
+    $menu_items = \Drupal::entityManager()->getStorageController('menu_link')->loadMultiple($menu_link_ids);
+    foreach ($menu_items as &$menu_item) {
+      _menu_link_translate($menu_item);
+    }
+    return $menu_items;
+  }
+
   /**
    * Test compact mode.
    */
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index ebcf07cc0f00082d3ddfd697fc3a1283cfe69523..37a30e4c71d7035ecab9e377745db4bdfb3ddc03 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -30,12 +30,6 @@ function system_theme_default() {
         ->set('default', $theme)
         ->save();
 
-      // Rebuild the menu. This duplicates the menu_router_rebuild() in
-      // theme_enable(). However, modules must know the current default theme in
-      // order to use this information in hook_menu() or hook_menu_alter()
-      // implementations, and saving the configuration before the theme_enable()
-      // could result in a race condition where the theme is default but not
-      // enabled.
       \Drupal::service('router.builder')->setRebuildNeeded();
 
       // The status message depends on whether an admin theme is currently in use:
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 63a848e885b8126a47ef93bd8d6a87d43a6dca68..b830cdee1e2fb4d800f218f95c11c87f1974c9b1 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -499,94 +499,6 @@ function hook_menu_link_defaults_alter(&$links) {
   $links['user.logout']['link_title'] = t('Logout');
 }
 
-/**
- * Define links for menus.
- *
- * @section sec_menu_link Creating Menu Items
- * Menu item example of type MENU_NORMAL_ITEM:
- * @code
- * // Make "Foo settings" appear on the admin Config page
- * $items['admin/config/system/foo'] = array(
- *   'title' => 'Foo settings',
- *   'type' => MENU_NORMAL_ITEM,
- *   'route_name' => 'foo.settings'
- * );
- * @endcode
- *
- * @todo The section that used to be here about path argument substitution has
- *   been removed, but is still referred to in the return section. It needs to
- *   be added back in, or a corrected version of it.
- *
- * @return
- *   An array of menu items. Each menu item has a key corresponding to the
- *   Drupal path being registered. The corresponding array value is an
- *   associative array that may contain the following key-value pairs:
- *   - "title": Required. The untranslated title of the menu item.
- *   - "title callback": Function to generate the title; defaults to t().
- *     If you require only the raw string to be output, set this to FALSE.
- *   - "title arguments": Arguments to send to t() or your custom callback,
- *     with path component substitution as described above.
- *   - "description": The untranslated description of the menu item.
- *   - description callback: Function to generate the description; defaults to
- *     t(). If you require only the raw string to be output, set this to FALSE.
- *   - description arguments: Arguments to send to t() or your custom callback,
- *     with path component substitution as described above.
- *   - "weight": An integer that determines the relative position of items in
- *     the menu; higher-weighted items sink. Defaults to 0. Menu items with the
- *     same weight are ordered alphabetically.
- *   - "menu_name": Optional. Set this to a custom menu if you don't want your
- *     item to be placed in the default Tools menu.
- *   - "expanded": Optional. If set to TRUE, and if a menu link is provided for
- *     this menu item (as a result of other properties), then the menu link is
- *     always expanded, equivalent to its 'always expanded' checkbox being set
- *     in the UI.
- *   - "position": Position of the block ('left' or 'right') on the system
- *     administration page for this item.
- *   - "type": A bitmask of flags describing properties of the menu item.
- *     Many shortcut bitmasks are provided as constants in menu.inc:
- *     - MENU_NORMAL_ITEM: Normal menu items show up in the menu tree and can be
- *       moved/hidden by the administrator.
- *     - MENU_SUGGESTED_ITEM: Modules may "suggest" menu items that the
- *       administrator may enable.
- *     If the "type" element is omitted, MENU_NORMAL_ITEM is assumed.
- *   - "options": An array of options to be passed to l() when generating a link
- *     from this menu item.
- *
- * For a detailed usage example, see page_example.module.
- * For comprehensive documentation on the menu system, see
- * http://drupal.org/node/102338.
- *
- * @see menu
- */
-function hook_menu() {
-  $items['example'] = array(
-    'title' => 'Example Page',
-    'route_name' => 'example.page',
-  );
-  $items['example/feed'] = array(
-    'title' => 'Example RSS feed',
-    'route_name' => 'example.feed',
-  );
-
-  return $items;
-}
-
-/**
- * Alter the data being saved to the {menu_router} table after hook_menu is invoked.
- *
- * This hook is invoked by menu_router_build(). The menu definitions are passed
- * in by reference. Each element of the $items array is one item returned
- * by a module from hook_menu. Additional items may be added, or existing items
- * altered.
- *
- * @param $items
- *   Associative array of menu router definitions returned from hook_menu().
- */
-function hook_menu_alter(&$items) {
-  // Example - disable the page at node/add
-  $items['node/add']['access callback'] = FALSE;
-}
-
 /**
  * Alter tabs and actions displayed on the page before they are rendered.
  *
@@ -1524,11 +1436,6 @@ function hook_cache_flush() {
  * system is known to return current information, so your module can safely rely
  * on all available data to rebuild its own.
  *
- * The menu router is the only exception regarding rebuilt data; it is only
- * rebuilt after all hook_rebuild() implementations have been invoked. That
- * ensures that hook_menu() implementations and the final router rebuild can
- * rely on all data being returned by all modules.
- *
  * @see hook_cache_flush()
  * @see drupal_flush_all_caches()
  */
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 2918e9d3784b8be4cd31495b13bba768c89f52ee..7a7208e1ead1c1b4428af0efcfc6bb7f8952e424 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -729,161 +729,6 @@ function system_schema() {
     ),
   );
 
-  $schema['menu_router'] = array(
-    'description' => 'Maps paths to various callbacks (access, page and title)',
-    'fields' => array(
-      'path' => array(
-        'description' => 'Primary Key: the Drupal path this entry describes',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'load_functions' => array(
-        'description' => 'A serialized array of function names (like node_load) to be called to load an object corresponding to a part of the current path.',
-        'type' => 'blob',
-        'not null' => TRUE,
-      ),
-      'to_arg_functions' => array(
-        'description' => 'A serialized array of function names (like user_uid_optional_to_arg) to be called to replace a part of the router path with another string.',
-        'type' => 'blob',
-        'not null' => TRUE,
-      ),
-      'access_callback' => array(
-        'description' => 'The callback which determines the access to this router path. Defaults to user_access.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'access_arguments' => array(
-        'description' => 'A serialized array of arguments for the access callback.',
-        'type' => 'blob',
-        'not null' => FALSE,
-      ),
-      'page_callback' => array(
-        'description' => 'The name of the function that renders the page.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'page_arguments' => array(
-        'description' => 'A serialized array of arguments for the page callback.',
-        'type' => 'blob',
-        'not null' => FALSE,
-      ),
-      'fit' => array(
-        'description' => 'A numeric representation of how specific the path is.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'number_parts' => array(
-        'description' => 'Number of parts in this router path.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'context' => array(
-        'description' => 'Only for local tasks (tabs) - the context of a local task to control its placement.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'tab_parent' => array(
-        'description' => 'Only for local tasks (tabs) - the router path of the parent page (which may also be a local task).',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'tab_root' => array(
-        'description' => 'Router path of the closest non-tab parent page. For pages that are not local tasks, this will be the same as the path.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'title' => array(
-        'description' => 'The title for the current page, or the title for the tab if this is a local task.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'title_callback' => array(
-        'description' => 'A function which will alter the title. Defaults to t()',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'title_arguments' => array(
-        'description' => 'A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'type' => array(
-        'description' => 'Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'description' => array(
-        'description' => 'A description of this item.',
-        'type' => 'text',
-        'not null' => TRUE,
-      ),
-      'description_callback' => array(
-        'description' => 'A function which will alter the description. Defaults to t().',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'description_arguments' => array(
-        'description' => 'A serialized array of arguments for the description callback. If empty, the description will be used as the sole argument for the description callback.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'position' => array(
-        'description' => 'The position of the block (left or right) on the system administration page for this item.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'weight' => array(
-        'description' => 'Weight of the element. Lighter weights are higher up, heavier weights go down.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'include_file' => array(
-        'description' => 'The file to include for this element, usually the page callback function lives in this file.',
-        'type' => 'text',
-        'size' => 'medium',
-      ),
-      'route_name' => array(
-        'description' => 'The machine name of a defined Symfony Route this menu item represents.',
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-    ),
-    'indexes' => array(
-      'fit' => array('fit'),
-      'tab_parent' => array(array('tab_parent', 64), 'weight', 'title'),
-      'tab_root_weight_title' => array(array('tab_root', 64), 'weight', 'title'),
-    ),
-    'primary key' => array('path'),
-  );
-
   $schema['queue'] = array(
     'description' => 'Stores items in queues.',
     'fields' => array(
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d36b68f3a3a49fee1c656eece6abd290823df3ec..34883922b42b16380196c6875fd52e9ac46ff7c5 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -626,206 +626,6 @@ function system_element_info() {
   return $types;
 }
 
-/**
- * Implements hook_menu().
- */
-function system_menu() {
-  $items['admin'] = array(
-    'title' => 'Administration',
-    'route_name' => 'system.admin',
-    'weight' => 9,
-    'menu_name' => 'admin',
-  );
-
-  // Menu items that are basically just menu blocks.
-  $items['admin/structure'] = array(
-    'title' => 'Structure',
-    'description' => 'Administer blocks, content types, menus, etc.',
-    'position' => 'right',
-    'weight' => -8,
-    'route_name' => 'system.admin_structure',
-  );
-  // Appearance.
-  $items['admin/appearance'] = array(
-    'title' => 'Appearance',
-    'description' => 'Select and configure your themes.',
-    'route_name' => 'system.themes_page',
-    'position' => 'left',
-    'weight' => -6,
-  );
-
-  // Modules.
-  $items['admin/modules'] = array(
-    'title' => 'Extend',
-    'description' => 'Add and enable modules to extend site functionality.',
-    'route_name' => 'system.modules_list',
-    'weight' => -2,
-  );
-
-  // Configuration.
-  $items['admin/config'] = array(
-    'title' => 'Configuration',
-    'description' => 'Administer settings.',
-    'route_name' => 'system.admin_config',
-  );
-
-  // Media settings.
-  $items['admin/config/media'] = array(
-    'title' => 'Media',
-    'description' => 'Media tools.',
-    'position' => 'left',
-    'weight' => -10,
-    'route_name' => 'system.admin_config_media',
-  );
-  $items['admin/config/media/file-system'] = array(
-    'title' => 'File system',
-    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
-    'route_name' => 'system.file_system_settings',
-    'weight' => -10,
-  );
-  $items['admin/config/media/image-toolkit'] = array(
-    'title' => 'Image toolkit',
-    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
-    'route_name' => 'system.image_toolkit_settings',
-    'weight' => 20,
-  );
-
-  // Service settings.
-  $items['admin/config/services'] = array(
-    'title' => 'Web services',
-    'description' => 'Tools related to web services.',
-    'position' => 'right',
-    'weight' => 0,
-    'route_name' => 'system.admin_config_services',
-  );
-  $items['admin/config/services/rss-publishing'] = array(
-    'title' => 'RSS publishing',
-    'description' => 'Configure the site description, the number of items per feed and whether feeds should be titles/teasers/full-text.',
-    'route_name' => 'system.rss_feeds_settings',
-  );
-
-  // Development settings.
-  $items['admin/config/development'] = array(
-    'title' => 'Development',
-    'description' => 'Development tools.',
-    'position' => 'right',
-    'weight' => -10,
-    'route_name' => 'system.admin_config_development',
-  );
-  $items['admin/config/development/maintenance'] = array(
-    'title' => 'Maintenance mode',
-    'description' => 'Take the site offline for maintenance or bring it back online.',
-    'route_name' => 'system.site_maintenance_mode',
-    'weight' => -10,
-  );
-  $items['admin/config/development/performance'] = array(
-    'title' => 'Performance',
-    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
-    'route_name' => 'system.performance_settings',
-    'weight' => -20,
-  );
-  $items['admin/config/development/logging'] = array(
-    'title' => 'Logging and errors',
-    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destinations, such as syslog, database, email, etc.",
-    'route_name' => 'system.logging_settings',
-    'weight' => -15,
-  );
-
-  // Regional and date settings.
-  $items['admin/config/regional'] = array(
-    'title' => 'Regional and language',
-    'description' => 'Regional settings, localization and translation.',
-    'position' => 'left',
-    'weight' => -5,
-    'route_name' => 'system.admin_config_regional',
-  );
-  $items['admin/config/regional/settings'] = array(
-    'title' => 'Regional settings',
-    'description' => "Settings for the site's default time zone and country.",
-    'route_name' => 'system.regional_settings',
-    'weight' => -20,
-  );
-  $items['admin/config/regional/date-time'] = array(
-    'title' => 'Date and time formats',
-    'description' => 'Configure display format strings for date and time.',
-    'route_name' => 'system.date_format_list',
-    'weight' => -5,
-  );
-  $items['admin/config/regional/date-time/formats/manage/%'] = array(
-    'title' => 'Edit date format',
-    'description' => 'Allow users to edit a configured date format.',
-    'route_name' => 'system.date_format_edit',
-  );
-
-  // Search settings.
-  $items['admin/config/search'] = array(
-    'title' => 'Search and metadata',
-    'description' => 'Local site search, metadata and SEO.',
-    'position' => 'left',
-    'weight' => -10,
-    'route_name' => 'system.admin_config_search',
-  );
-
-  // System settings.
-  $items['admin/config/system'] = array(
-    'title' => 'System',
-    'description' => 'General system related configuration.',
-    'position' => 'right',
-    'weight' => -20,
-    'route_name' => 'system.admin_config_system',
-  );
-  $items['admin/config/system/site-information'] = array(
-    'title' => 'Site information',
-    'description' => 'Change site name, e-mail address, slogan, default front page and error pages.',
-    'route_name' => 'system.site_information_settings',
-    'weight' => -20,
-  );
-  $items['admin/config/system/cron'] = array(
-    'title' => 'Cron',
-    'description' => 'Manage automatic site maintenance tasks.',
-    'route_name' => 'system.cron_settings',
-    'weight' => 20,
-  );
-  // Additional categories
-  $items['admin/config/user-interface'] = array(
-    'title' => 'User interface',
-    'description' => 'Tools that enhance the user interface.',
-    'position' => 'right',
-    'route_name' => 'system.admin_config_ui',
-    'weight' => -15,
-  );
-  $items['admin/config/workflow'] = array(
-    'title' => 'Workflow',
-    'description' => 'Content workflow, editorial workflow tools.',
-    'position' => 'right',
-    'weight' => 5,
-    'route_name' => 'system.admin_config_workflow',
-  );
-  $items['admin/config/content'] = array(
-    'title' => 'Content authoring',
-    'description' => 'Settings related to formatting and authoring content.',
-    'position' => 'left',
-    'weight' => -15,
-    'route_name' => 'system.admin_config_content',
-  );
-
-  // Reports.
-  $items['admin/reports'] = array(
-    'title' => 'Reports',
-    'description' => 'View reports, updates, and errors.',
-    'route_name' => 'system.admin_reports',
-    'weight' => 5,
-    'position' => 'left',
-  );
-  $items['admin/reports/status'] = array(
-    'title' => 'Status report',
-    'description' => "Get a status report about your site's operation and any detected problems.",
-    'route_name' => 'system.status',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -849,12 +649,14 @@ function system_menu_link_defaults() {
   $items['system.admin.appearance'] = array(
     'route_name' => 'system.themes_page',
     'link_title' => 'Appearance',
+    'description' => 'Select and configure your themes.',
     'parent' => 'system.admin',
     'weight' => -6,
   );
   // Modules.
   $items['system.admin.modules'] = array(
     'link_title' => 'Extend',
+    'description' => 'Add and enable modules to extend site functionality.',
     'parent' => 'system.admin',
     'route_name' => 'system.modules_list',
     'weight' => -2,
diff --git a/core/modules/system/tests/modules/batch_test/batch_test.module b/core/modules/system/tests/modules/batch_test/batch_test.module
index ba8b273a576ffbb4b2b735d50e6d449cf1bce67a..b97f96655daaca3170a17dec79b5bd73712f246a 100644
--- a/core/modules/system/tests/modules/batch_test/batch_test.module
+++ b/core/modules/system/tests/modules/batch_test/batch_test.module
@@ -5,20 +5,6 @@
  * Helper module for the Batch API tests.
  */
 
-/**
- * Implements hook_menu().
- */
-function batch_test_menu() {
-  $items = array();
-
-  $items['batch-test'] = array(
-    'title' => 'Batch test',
-    'route_name' => 'batch_test.test_form',
-  );
-
-  return $items;
-}
-
 /**
  * Form constructor for a batch selection form.
  *
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 9620ef50b572e351852f46009761c88c3330b823..9bcc69f46662f3a60e1ad6c010f5dc1a139ce318 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -239,30 +239,6 @@ function entity_test_permission() {
   return $permissions;
 }
 
-/**
- * Implements hook_menu().
- */
-function entity_test_menu() {
-  $items = array();
-  $types = entity_test_entity_types();
-
-  foreach($types as $entity_type) {
-    $items[$entity_type . '/add'] = array(
-      'title' => 'Add an @type',
-      'title arguments' => array('@type' => $entity_type),
-      'route_name' => "entity_test.add_$entity_type",
-    );
-
-    $items[$entity_type . '/manage/%' . $entity_type] = array(
-      'title' => 'Edit @type',
-      'title arguments' => array('@type' => $entity_type),
-      'route_name' => "entity_test.edit_$entity_type",
-    );
-  }
-
-  return $items;
-}
-
 /**
  * Implements hook_form_BASE_FORM_ID_alter().
  */
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module
index 30dffdc37af505b95c6cd4e63a873ee56548eb47..08e6382522413bb21433d1871cdc697a4d1d4480 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.module
+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -7,147 +7,6 @@
 
 use Drupal\menu_link\Entity\MenuLink;
 
-/**
- * Implements hook_menu().
- */
-function menu_test_menu() {
-  // The name of the menu changes during the course of the test. Using a GET.
-  $items['menu_name_test'] = array(
-    'title' => 'Test menu_name router item',
-    'route_name' => 'menu_test.menu_name_test',
-    'menu_name' => menu_test_menu_name(),
-  );
-  // This item uses SystemController::systemAdminMenuBlockPage() to list child
-  // items.
-  $items['menu_callback_description'] = array(
-    'title' => 'Menu item title',
-    'description' => 'Menu item description parent',
-    'route_name' => 'menu_test.callback_description',
-  );
-  // This item tests the description key.
-  $items['menu_callback_description/description-plain'] = array(
-    'title' => 'Menu item with a regular description',
-    'description' => 'Menu item description text',
-    'route_name' => 'menu_test.callback_description_plain',
-  );
-  // This item tests using a description callback.
-  $items['menu_callback_description/description-callback'] = array(
-    'title' => 'Menu item with a description set with a callback',
-    'description callback' => 'check_plain',
-    'description arguments' => array('<strong>Menu item description arguments</strong>'),
-    'route_name' => 'menu_test.callback_description_callback',
-  );
-  // Use FALSE as 'title callback' to bypass t().
-  $items['menu_no_title_callback'] = array(
-    'title' => 'A title with @placeholder',
-    'title callback' => FALSE,
-    'title arguments' => array('@placeholder' => 'some other text'),
-    'route_name' => 'menu_test.menu_no_title_callback',
-  );
-
-  // Hidden link for menu_link_maintain tests
-  $items['menu_test_maintain/%'] = array(
-    'title' => 'Menu maintain test',
-    'route_name' => 'menu_test.menu_test_maintain',
-   );
-  // Hierarchical tests.
-  $items['menu-test/hierarchy/parent'] = array(
-    'title' => 'Parent menu router',
-    'route_name' => 'menu_test.hierarchy_parent',
-  );
-  $items['menu-test/hierarchy/parent/child'] = array(
-    'title' => 'Child menu router',
-    'route_name' => 'menu_test.hierarchy_parent_child',
-  );
-  $items['menu-test/hierarchy/parent/child2/child'] = array(
-    'title' => 'Unattached subchild router',
-    'route_name' => 'menu_test.hierarchy_parent_child2',
-  );
-  // Theme callback tests.
-  $items['menu-test/theme-callback/%/inheritance'] = array(
-    'title' => 'Page that tests theme negotiation inheritance.',
-    'route_name' => 'menu_test.theme_callback_inheritance',
-  );
-  $items['menu-test/no-theme-callback'] = array(
-    'title' => 'Page that displays different themes without using a theme negotiation.',
-    'route_name' => 'menu_test.no_theme_callback',
-  );
-  // Path containing "exotic" characters.
-  $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
-    "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
-    "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
-  $items[$path] = array(
-    'title' => '"Exotic" path',
-    'route_name' => 'menu_test.exotic_path',
-  );
-
-  // Hidden tests; base parents.
-  // Same structure as in Menu and Block modules. Since those structures can
-  // change, we need to simulate our own in here.
-  $items['menu-test'] = array(
-    'title' => 'Menu test root',
-    'route_name' => 'menu_test.menu_test',
-  );
-
-  // Menu trail tests.
-  // @see MenuTrailTestCase
-  $items['menu-test/menu-trail'] = array(
-    'title' => 'Menu trail - Case 1',
-    'route_name' => 'menu_test.menu_trail',
-  );
-  $items['admin/config/development/menu-trail'] = array(
-    'title' => 'Menu trail - Case 2',
-    'description' => 'Tests menu_tree_set_path()',
-    'route_name' => 'menu_test.menu_trail_admin',
-  );
-  $items['menu-test/custom-403-page'] = array(
-    'title' => 'Custom 403 page',
-    'route_name' => 'menu_test.custom_403',
-  );
-  $items['menu-test/custom-404-page'] = array(
-    'title' => 'Custom 404 page',
-    'route_name' => 'menu_test.custom_404',
-  );
-
-  // Test the access key.
-  $items['menu-title-test/case1'] = array(
-    'title' => 'Example title - Case 1',
-    'route_name' => 'menu_test.title_test_case1',
-  );
-  $items['menu-title-test/case2'] = array(
-    'title' => 'Example title',
-    'title callback' => 'menu_test_title_callback',
-    'route_name' => 'menu_test.title_test_case2',
-  );
-  $items['menu-title-test/case3'] = array(
-    // Title gets completely ignored. Good thing, too.
-    'title' => 'Bike sheds full of blue smurfs WRONG',
-    'route_name' => 'menu_test.title_test_case3',
-  );
-
-  $items['menu-test-local-action'] = array(
-    'title' => 'Local action parent',
-    'route_name' => 'menu_test.local_action1',
-  );
-
-  $items['menu-local-task-test/tasks'] = array(
-    'title' => 'Local tasks',
-    'route_name' => 'menu_test.local_task_test_tasks',
-  );
-  $items['menu-test/optional'] = array(
-    'title' => 'Test optional placeholder',
-    'route_name' => 'menu_test.optional_placeholder',
-    'type' => MENU_LOCAL_TASK,
-  );
-
-  $items['menu-test/context'] = array(
-    'title' => \Drupal::config('menu_test.menu_item')->get('title'),
-    'route_name' => 'menu_test.context',
-  );
-
-  return $items;
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -172,12 +31,6 @@ function menu_test_menu_link_defaults() {
     'route_name' => 'menu_test.callback_description_plain',
     'parent' => 'menu_test.menu_callback_description',
   );
-  // This item tests using a description callback.
-  $items['menu_callback_description.description-callback'] = array(
-    'link_title' => 'Menu item with a description set with a callback',
-    'route_name' => 'menu_test.callback_description_callback',
-    'parent' => 'menu_test.menu_callback_description',
-  );
 
   $items['menu_test.menu_no_title_callback'] = array(
     'link_title' => 'A title with @placeholder',
@@ -337,36 +190,6 @@ function menu_test_menu_local_tasks_alter(&$data, $route_name) {
   }
 }
 
-/**
- * Argument callback: Loads an argument using a function for hook_menu().
- *
- * @param string $arg1
- *   A parameter passed in via the URL.
- *
- * @return false
- *   Always return NULL.
- *
- * @see menu_test_menu();
- */
-function menu_test_argument_load($arg1) {
-  return NULL;
-}
-
-/**
- * Argument callback: Loads an argument using a function for hook_menu().
- *
- * @param string $arg1
- *   A parameter passed in via the URL.
- *
- * @return false
- *   Always return NULL.
- *
- * @see menu_test_menu();
- */
-function menu_test_other_argument_load($arg1) {
-  return NULL;
-}
-
 /**
  * Page callback: Provides a dummy function which can be used as a placeholder.
  *
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
index 637be3c1ade2ed487374c6aba7284c3470996372..34d5dadc45482cec80c56dd6fe12eb944c61545a 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
@@ -36,14 +36,6 @@ menu_test.callback_description_plain:
   requirements:
     _access: 'TRUE'
 
-menu_test.callback_description_callback:
-  path: '/menu_callback_description/description-callback'
-  defaults:
-    _title: 'Menu item with a description set with a callback'
-    _content: '\Drupal\menu_test\Controller\MenuTestController::menuTestCallback'
-  requirements:
-    _access: 'TRUE'
-
 menu_test.menu_no_title_callback:
   path: '/menu_no_title_callback'
   defaults:
diff --git a/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php
index e234afbf59f71275e2437a7d33c3b8b8f3eec02a..eff984ba07153d13a83b284afe325f38225a6d88 100644
--- a/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php
+++ b/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php
@@ -21,6 +21,6 @@ class RegisterAccessCheck implements AccessInterface {
    * Implements AccessCheckInterface::access().
    */
   public function access(Route $route, Request $request, AccountInterface $account) {
-    return ($account->isAnonymous() && (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY)) ? static::ALLOW : static::DENY;
+    return ($request->attributes->get('_menu_admin') || $account->isAnonymous()) && (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) ? static::ALLOW : static::DENY;
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/lib/Drupal/user/EventSubscriber/MaintenanceModeSubscriber.php
index 0a42c917be0fdc36d37c0ca7cdb6175c253d9bea..3c478f7b6075cdc1c5a7941f217b71c37cb02dc4 100644
--- a/core/modules/user/lib/Drupal/user/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/modules/user/lib/Drupal/user/EventSubscriber/MaintenanceModeSubscriber.php
@@ -37,7 +37,7 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
         return;
       }
 
-      if (user_is_anonymous()) {
+      if ($user->isAnonymous()) {
         switch ($path) {
           case 'user':
             // Forward anonymous user to login page.
diff --git a/core/modules/user/tests/modules/user_form_test/user_form_test.module b/core/modules/user/tests/modules/user_form_test/user_form_test.module
index 134804f45948d23fbb74da3afaeb6d81d77f95e9..aefc9d3538f64f8f5a1636b9bd1c59d8fe7463e9 100644
--- a/core/modules/user/tests/modules/user_form_test/user_form_test.module
+++ b/core/modules/user/tests/modules/user_form_test/user_form_test.module
@@ -4,18 +4,3 @@
  * @file
  * Dummy module implementing a form to test user password validation
  */
-
-/**
- * Implements hook_menu().
- *
- * Sets up a form that allows a user to validate password.
- */
-function user_form_test_menu() {
-  $items = array();
-  $items['user_form_test_current_password/%user'] = array(
-    'title' => 'User form test for current password validation',
-    'route_name' => 'user_form_test.current_password',
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  return $items;
-}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 9b2194b32cce042136cbbc4dce4ace435baf82e9..c8b51b7d013797df13a554110c8316044827eef6 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -685,40 +685,6 @@ function theme_username($variables) {
   return $output;
 }
 
-/**
- * Determines if the current user is anonymous.
- *
- * @return bool
- *   TRUE if the user is anonymous, FALSE if the user is authenticated.
- */
-function user_is_anonymous() {
-  // Menu administrators can see items for anonymous when administering.
-  return $GLOBALS['user']->isAnonymous() || !empty($GLOBALS['menu_admin']);
-}
-
-/**
- * Determines if the current user is logged in.
- *
- * @return bool
- *   TRUE if the user is logged in, FALSE if the user is anonymous.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- *   Use \Drupal\Core\Session\UserSession::isAuthenticated().
- */
-function user_is_logged_in() {
-  return $GLOBALS['user']->isAuthenticated();
-}
-
-/**
- * Determines if the current user has access to the user registration page.
- *
- * @return bool
- *   TRUE if the user is not already logged in and can register for an account.
- */
-function user_register_access() {
-  return user_is_anonymous() && (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY);
-}
-
 /**
  * Implements hook_menu_link_defaults().
  */
@@ -816,81 +782,6 @@ function user_admin_paths() {
   return $paths;
 }
 
-/**
- * Returns $arg or the user ID of the current user if $arg is '%' or empty.
- *
- * Deprecated. Use %user_uid_optional instead.
- *
- * @todo D8: Remove.
- */
-function user_uid_only_optional_to_arg($arg) {
-  return user_uid_optional_to_arg($arg);
-}
-
-/**
- * Load either a specified or the current user account.
- *
- * @param $uid
- *   An optional user ID of the user to load. If not provided, the current
- *   user's ID will be used.
- * @return
- *   A fully-loaded $user object upon successful user load, NULL if user
- *   cannot be loaded.
- *
- * @see user_load()
- * @todo rethink the naming of this in Drupal 8.
- */
-function user_uid_optional_load($uid = NULL) {
-  if (!isset($uid)) {
-    $uid = $GLOBALS['user']->id();
-  }
-  return user_load($uid);
-}
-
-/**
- * Returns $arg or the user ID of the current user if $arg is '%' or empty.
- *
- * @todo rethink the naming of this in Drupal 8.
- */
-function user_uid_optional_to_arg($arg) {
-  // Give back the current user uid when called from eg. tracker, aka.
-  // with an empty arg. Also use the current user uid when called from
-  // the menu with a % for the current account link.
-  return empty($arg) || $arg == '%' ? $GLOBALS['user']->id() : $arg;
-}
-
-/**
- * Menu item title callback for the 'user' path.
- *
- * Anonymous users should see a title based on the requested page, but
- * authenticated users are expected to see "My account".
- */
-function user_menu_title() {
-  if ($GLOBALS['user']->isAnonymous()) {
-    switch (current_path()) {
-      case 'user' :
-      case 'user/login' :
-        return t('Log in');
-      case 'user/register' :
-        return t('Create new account');
-      case 'user/password' :
-        return t('Request new password');
-      default :
-        return t('User account');
-    }
-  }
-  else {
-    return t('My account');
-  }
-}
-
-/**
- * Menu item title callback - use the user name.
- */
-function user_page_title(UserInterface $account = NULL) {
-  return $account ? $account->getUsername() : '';
-}
-
 /**
  * Try to validate the user's login credentials locally.
  *
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 7b22ce9584373a8d1e6433ce4f24ae88cf188888..ac2f70695b14bdd92329fc15f4e8fea80344388c 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
@@ -327,121 +327,6 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
     return $links;
   }
 
-  /**
-   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::executeHookMenu().
-   */
-  public function executeHookMenu($callbacks) {
-    $items = array();
-    // Replace % with the link to our standard views argument loader
-    // views_arg_load -- which lives in views.module.
-
-    $bits = explode('/', $this->getOption('path'));
-    $page_arguments = array($this->view->storage->id(), $this->display['id']);
-    $this->view->initHandlers();
-    $view_arguments = $this->view->argument;
-
-    $path = implode('/', $bits);
-
-    $view_route_names = $this->state->get('views.view_route_names') ?: array();
-
-    if ($path) {
-      // Some views might override existing paths, so we have to set the route
-      // name based upon the altering.
-      $view_id_display =  "{$this->view->storage->id()}.{$this->display['id']}";
-      $items[$path] = array(
-        'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
-        // Identify URL embedded arguments and correlate them to a handler.
-        'load arguments'  => array($this->view->storage->id(), $this->display['id'], '%index'),
-      );
-      $menu = $this->getOption('menu');
-      if (empty($menu)) {
-        $menu = array('type' => 'none');
-      }
-      // Set the title and description if we have one.
-      if ($menu['type'] != 'none') {
-        $items[$path]['title'] = $menu['title'];
-        $items[$path]['description'] = $menu['description'];
-      }
-
-      if (isset($menu['weight'])) {
-        $items[$path]['weight'] = intval($menu['weight']);
-      }
-
-      switch ($menu['type']) {
-        case 'none':
-        default:
-          $items[$path]['type'] = MENU_CALLBACK;
-          break;
-        case 'normal':
-          $items[$path]['type'] = MENU_NORMAL_ITEM;
-          // Insert item into the proper menu.
-          $items[$path]['menu_name'] = $menu['name'];
-          break;
-        case 'tab':
-          $items[$path]['type'] = MENU_CALLBACK;
-          break;
-        case 'default tab':
-          $items[$path]['type'] = MENU_CALLBACK;
-          break;
-      }
-
-      // Add context for contextual links.
-      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'] = TRUE;
-        }
-      }
-
-      // If this is a 'default' tab, check to see if we have to create the
-      // parent menu item.
-      if ($this->isDefaultTabPath()) {
-        $tab_options = $this->getOption('tab_options');
-
-        $bits = explode('/', $path);
-        // 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 (!empty($bits)) {
-          // Assign the route name to the parent route, not the default tab.
-          $default_route_name = $items[$path]['route_name'];
-          unset($items[$path]['route_name']);
-
-          $default_path = implode('/', $bits);
-          $items[$default_path] = array(
-            // Default views page entry.
-            // Identify URL embedded arguments and correlate them to a
-            // handler.
-            'load arguments'  => array($this->view->storage->id(), $this->display['id'], '%index'),
-            'title' => $tab_options['title'],
-            'description' => $tab_options['description'],
-            'menu_name' => $tab_options['name'],
-            'route_name' => $default_route_name,
-          );
-          switch ($tab_options['type']) {
-            default:
-            case 'normal':
-              $items[$default_path]['type'] = MENU_NORMAL_ITEM;
-              break;
-          }
-          if (isset($tab_options['weight'])) {
-            $items[$default_path]['weight'] = intval($tab_options['weight']);
-          }
-        }
-      }
-    }
-
-    return $items;
-  }
-
   /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::execute().
    */
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorStringTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorStringTest.php
index 75c7b65db161c3dce346bff48d23b8f5762910ee..079e0031a14b3861d105526c68dd2307f1d0fd7b 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorStringTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorStringTest.php
@@ -49,7 +49,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorTest.php
index 1ef7ca860e9338bb375da24c60b6f1645c1a6e3c..a9ff2cf89df2b25cd2664337e1013e3e193e995a 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterBooleanOperatorTest.php
@@ -45,7 +45,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
   /**
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
index 0c0c5179f675c00776592cc462df79212475a7cd..f2397739b158436ab69ebb72feee933e15f87ba3 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
@@ -38,7 +38,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
   function viewsData() {
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
index bd024e2ace3bd75b4c2107c6115334162b03ef12..7c710e32c6ca82738aaad873d5d267e113e67f46 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
@@ -39,7 +39,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
   function viewsData() {
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
index ad0a627465443a6065b0c45ec037d17fe83943c4..ae187500057cad74e16a5691b34093778b076522 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
@@ -39,7 +39,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
   function viewsData() {
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
index 5a62bed44f5c580a2f6c577f1e6dd6c0cb785c72..8d7e1f587a0ec6124eb1d7c966a2af5d59a679a6 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
@@ -38,7 +38,7 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router', 'key_value_expire'));
+    $this->installSchema('system', array('key_value_expire'));
   }
 
   function viewsData() {
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
index 5867c982376467349983bb4f3742e899360fcc7c..48ad3f2ebeaebb1c7321b93c6203130ab1b77c04 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
@@ -54,7 +54,7 @@ protected function setUp() {
     parent::setUp();
 
     // Setup the needed tables in order to make the drupal router working.
-    $this->installSchema('system', array('menu_router', 'url_alias'));
+    $this->installSchema('system', array('url_alias'));
     $this->installSchema('menu_link', 'menu_links');
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/RowEntityTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/RowEntityTest.php
index 807880a651fd3c89ddc48759ee94433bcb171872..5efa290225265b05d8809fd9ba7d27ac4e5560ee 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/RowEntityTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/RowEntityTest.php
@@ -51,7 +51,6 @@ public static function getInfo() {
   protected function setUp() {
     parent::setUp();
 
-    $this->installSchema('system', array('menu_router'));
     $this->installSchema('taxonomy', array('taxonomy_term_data', 'taxonomy_term_hierarchy'));
     $this->installConfig(array('taxonomy'));
     \Drupal::service('router.builder')->rebuild();
diff --git a/core/modules/views/lib/Drupal/views/ViewExecutable.php b/core/modules/views/lib/Drupal/views/ViewExecutable.php
index 6fa98d271a0ff078f619b580cbb17031b38a714e..17131c4568b2c5e6986c1016323562cf5cb1236e 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -1511,28 +1511,6 @@ public function attachDisplays() {
     $this->is_attachment = FALSE;
   }
 
-  /**
-   * Called to get hook_menu() information from the view and the named display handler.
-   *
-   * @param $display_id
-   *   A display id.
-   * @param $callbacks
-   *   A menu callback array passed from views_menu_alter().
-   */
-  public function executeHookMenu($display_id = NULL, &$callbacks = array()) {
-    // Prepare the view with the information we have.
-
-    // This was probably already called, but it's good to be safe.
-    if (!$this->setDisplay($display_id)) {
-      return FALSE;
-    }
-
-    // Execute the view
-    if (isset($this->display_handler)) {
-      return $this->display_handler->executeHookMenu($callbacks);
-    }
-  }
-
   /**
    * Returns default menu links from the view and the named display handler.
    *