diff --git a/core/core.services.yml b/core/core.services.yml
index 0c038ec..720f629 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -302,6 +302,11 @@ services:
     calls:
       - [setContext, ['@router.request_context']]
       - [add, ['@router.dynamic']]
+  router.path_roots_subscriber:
+    class: Drupal\Core\EventSubscriber\PathRootsSubscriber
+    arguments: ['@state']
+    tags:
+      - { name: event_subscriber }
   entity.query:
     class: Drupal\Core\Entity\Query\QueryFactory
     arguments: ['@entity.manager']
@@ -321,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 668d689..ddbaca2 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -13,6 +13,7 @@
 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;
@@ -43,9 +44,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!
@@ -311,78 +312,6 @@
 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
@@ -432,108 +361,6 @@ function menu_unserialize($data, $map) {
 }
 
 /**
- * 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.
  *
  * Translate the title and description to allow storage of English title
@@ -561,7 +388,10 @@ function _menu_check_access(&$item, $map) {
  *   (link title attribute) matches the description, it is translated as well.
  */
 function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
-  $title_callback = $item['title_callback'];
+  // 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.
@@ -580,6 +410,8 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
   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']);
@@ -655,134 +487,28 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
  *
  * @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.
+ * @param string
+ *   The path.
  */
-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();
+function _menu_translate(&$router_item, $path) {
   // 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);
-  }
-  else {
-    // @todo: Remove once all routes are converted.
-    _menu_check_access($router_item, $map);
-  }
+  $route = \Drupal::service('router.route_provider')->getRouteByName($router_item['route_name']);
+  $request = RequestHelper::duplicate(\Drupal::request(), '/' . $path);
+  $request->attributes->set('_system_path', $path);
+  $router_item['access'] = menu_item_route_access($route, $request);
 
   // For performance, don't localize an item the user can't access.
   if ($router_item['access']) {
+    $map = explode('/', $path);
     _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]);
-    }
-  }
-}
-
-/**
- * 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).
+ * link-specific preparation.
  *
  * @param array $item
  *   The passed in item has the following keys:
@@ -840,10 +566,6 @@ function _menu_link_translate(&$item) {
  *
  * @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.
  *
@@ -852,11 +574,7 @@ function _menu_link_translate(&$item) {
  *   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);
-  }
+function menu_item_route_access(Route $route, Request $request) {
   // Attempt to match this path to provide a fully built request to the
   // access checker.
   try {
@@ -866,31 +584,12 @@ function menu_item_route_access(Route $route, $href, &$map, Request $request = N
     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.
  *
@@ -2058,8 +1757,7 @@ 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);
+            _menu_translate($candidate_item, $path);
             if ($candidate_item['access']) {
               $preferred_links[$path][$menu_name] = $candidate_item;
               if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
@@ -2123,139 +1821,6 @@ function menu_reset_static_cache() {
 }
 
 /**
- * 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 (!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.
-    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);
-  }
-
-  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().
  */
 function _menu_link_save_recursive($controller, $machine_name, &$children, &$links) {
@@ -2395,7 +1960,7 @@ function menu_link_rebuild_defaults() {
   if ($all_links) {
     $query = \Drupal::entityQuery('menu_link')
       ->condition('machine_name', array_keys($all_links), 'NOT IN')
-      ->condition('machine_name', NULL, '<>')
+      ->exists('machine_name')
       ->condition('external', 0)
       ->condition('updated', 0)
       ->condition('customized', 0)
@@ -2481,358 +2046,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 912610d..ef169f4 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -183,57 +183,30 @@ 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) {
+  $is_valid = FALSE;
+  // External URLs and the front page are always valid.
   if ($path == '<front>' || url_is_external($path)) {
-    $item = array('access' => TRUE);
+    $is_valid = TRUE;
   }
-  elseif (($collection = $route_provider->getRoutesByPattern('/' . $router_path)) && $collection->count() > 0) {
+
+  // Check the routing system.
+  elseif (($collection = \Drupal::service('router.route_provider')->getRoutesByPattern('/' . $path)) && $collection->count() > 0) {
     $routes = $collection->all();
-    $route_name = key($routes);
-  }
-  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'];
-    }
-  }
-  // Check the new routing system.
-  if (!empty($route_name)) {
-    $map = array();
-    $route = \Drupal::service('router.route_provider')->getRouteByName($route_name);
+    $route = reset($routes);
     $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);
+    // We indicate that a menu administrator is running the menu access check.
+    $request->attributes->set('_menu_admin', TRUE);
+    $is_valid = menu_item_route_access($route, $request);
   }
-  $menu_admin = FALSE;
-  return !empty($item['access']);
+  return $is_valid;
 }
diff --git a/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php
new file mode 100644
index 0000000..f2701bc
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/PathRootsSubscriber.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\PathRootsSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\KeyValueStore\StateInterface;
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Provides all available first bits of all route paths.
+ */
+class PathRootsSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Stores the path roots available in the router.
+   *
+   * A path root is the first virtual directory of a path, like 'admin', 'node'
+   * or 'user'.
+   *
+   * @var array
+   */
+  protected $pathRoots;
+
+  /**
+   * The state key value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Constructs a new PathRootsSubscriber instance.
+   *
+   * @param \Drupal\Core\KeyValueStore\StateInterface $state
+   *   The state key value store.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * Collects all path roots.
+   *
+   * @param \Drupal\Core\Routing\RouteBuildEvent $event
+   *   The route build event.
+   */
+  public function onRouteAlter(RouteBuildEvent $event) {
+    $collection = $event->getRouteCollection();
+    foreach ($collection->all() as $route) {
+      $bits = explode('/', ltrim($route->getPath(), '/'));
+      $this->pathRoots[$bits[0]] = $bits[0];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onRouteFinished() {
+    $this->state->set('router.path_roots', array_keys($this->pathRoots));
+    unset($this->pathRoots);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events = array();
+    // Try to set a low priority to ensure that all routes are already added.
+    $events[RoutingEvents::ALTER][] = array('onRouteAlter', -1024);
+    $events[RoutingEvents::FINISHED][] = array('onRouteFinished');
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
index d432656bf..0d59329 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 router and runs menu-specific code if necessary.
  */
 class RouterRebuildSubscriber implements EventSubscriberInterface {
 
@@ -26,13 +27,21 @@ 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;
   }
 
   /**
@@ -52,11 +61,39 @@ public function onKernelTerminate(PostResponseEvent $event) {
    *   The event object.
    */
   public function onRouterRebuild(Event $event) {
-    menu_router_rebuild();
+    $this->menuRouterRebuild();
     Cache::deleteTags(array('local_task' => 1));
   }
 
   /**
+   * Perform menu-specific rebuilding.
+   */
+  protected function menuRouterRebuild() {
+    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.
    *
    * @return array
diff --git a/core/lib/Drupal/Core/Path/AliasWhitelist.php b/core/lib/Drupal/Core/Path/AliasWhitelist.php
index e748315..b990c3b 100644
--- a/core/lib/Drupal/Core/Path/AliasWhitelist.php
+++ b/core/lib/Drupal/Core/Path/AliasWhitelist.php
@@ -60,7 +60,7 @@ protected function lazyLoadCache() {
 
     // On a cold start $this->storage will be empty and the whitelist will
     // need to be rebuilt from scratch. The whitelist is initialized from the
-    // list of all valid path roots stored in the 'menu_path_roots' state,
+    // list of all valid path roots stored in the 'router.path_roots' state,
     // with values initialized to NULL. During the request, each path requested
     // that matches one of these keys will be looked up and the array value set
     // to either TRUE or FALSE. This ensures that paths which do not exist in
@@ -75,7 +75,7 @@ protected function lazyLoadCache() {
    * Loads menu path roots to prepopulate cache.
    */
   protected function loadMenuPathRoots() {
-    if ($roots = $this->state->get('menu_path_roots')) {
+    if ($roots = $this->state->get('router.path_roots')) {
       foreach ($roots as $root) {
         $this->storage[$root] = NULL;
         $this->persist($root);
diff --git a/core/modules/action/action.module b/core/modules/action/action.module
index 07e7b48..ee2f628 100644
--- a/core/modules/action/action.module
+++ b/core/modules/action/action.module
@@ -45,18 +45,6 @@ function action_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function action_menu() {
-  $items['admin/config/system/actions'] = array(
-    'title' => 'Actions',
-    'description' => 'Manage the actions defined for your site.',
-    'route_name' => 'action.admin',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function action_menu_link_defaults() {
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index d6d701e..fce70cb 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -88,48 +88,6 @@ function aggregator_theme() {
 }
 
 /**
- * Implements hook_menu().
- */
-function aggregator_menu() {
-  $items['admin/config/services/aggregator'] = array(
-    'title' => 'Feed aggregator',
-    'description' => "Configure which content your site aggregates from other sites, and how often it polls them.",
-    'route_name' => 'aggregator.admin_overview',
-    'weight' => 10,
-  );
-  $items['admin/config/services/aggregator/remove/%aggregator_feed'] = array(
-    'title' => 'Remove items',
-    'route_name' => 'aggregator.feed_items_delete',
-  );
-  $items['admin/config/services/aggregator/update/%aggregator_feed'] = array(
-    'title' => 'Update items',
-    'route_name' => 'aggregator.feed_refresh',
-  );
-  $items['aggregator'] = array(
-    'title' => 'Feed aggregator',
-    'weight' => 5,
-    'route_name' => 'aggregator.page_last',
-  );
-  $items['aggregator/sources'] = array(
-    'title' => 'Sources',
-    'route_name' => 'aggregator.sources',
-  );
-  $items['aggregator/sources/%aggregator_feed'] = array(
-    'route_name' => 'aggregator.feed_view',
-  );
-  $items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
-    'title' => 'Edit feed',
-    'route_name' => 'aggregator.feed_edit',
-  );
-  $items['admin/config/services/aggregator/delete/feed/%aggregator_feed'] = array(
-    'title' => 'Delete feed',
-    'route_name' => 'aggregator.feed_delete',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function aggregator_menu_link_defaults() {
diff --git a/core/modules/ban/ban.module b/core/modules/ban/ban.module
index 7d09e7c..e45ed13 100644
--- a/core/modules/ban/ban.module
+++ b/core/modules/ban/ban.module
@@ -38,23 +38,6 @@ function ban_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function ban_menu() {
-  $items['admin/config/people/ban'] = array(
-    'title' => 'IP address bans',
-    'description' => 'Manage banned IP addresses.',
-    'route_name' => 'ban.admin_page',
-    'weight' => 10,
-  );
-  $items['admin/config/people/ban/delete/%'] = array(
-    'title' => 'Delete IP address',
-    'route_name' => 'ban.delete',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function ban_menu_link_defaults() {
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 79fe59f..282b891 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/block.module b/core/modules/block/block.module
index 2ee5f48..e97852c 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -93,29 +93,6 @@ function block_permission() {
 }
 
 /**
- * Implements hook_menu().
- *
- * @todo Clarify the documentation for the per-plugin block admin links.
- */
-function block_menu() {
-  $items['admin/structure/block'] = array(
-    'title' => 'Block layout',
-    'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
-    'route_name' => 'block.admin_display',
-  );
-  $items['admin/structure/block/manage/%block'] = array(
-    'title' => 'Configure block',
-    'route_name' => 'block.admin_edit',
-  );
-  $items['admin/structure/block/add/%/%'] = array(
-    'title' => 'Place block',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-    'route_name' => 'block.admin_add',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function block_menu_link_defaults() {
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index 2365ded..633e9fb 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -38,33 +38,6 @@ function custom_block_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function custom_block_menu() {
-  $items['admin/structure/block/custom-blocks'] = array(
-    'title' => 'Custom block library',
-    'description' => 'Manage custom blocks.',
-    'route_name' => 'custom_block.list',
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  $items['admin/structure/block/custom-blocks/manage/%custom_block_type'] = array(
-    'title' => 'Edit custom block type',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-    'route_name' => 'custom_block.type_edit',
-  );
-
-  $items['block/add'] = array(
-    'title' => 'Add custom block',
-    'description' => 'Add custom block',
-    'route_name' => 'custom_block.add_page',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function custom_block_menu_link_defaults() {
@@ -73,6 +46,11 @@ function custom_block_menu_link_defaults() {
     'description' => 'Add custom block',
     'route_name' => 'custom_block.add_page',
   );
+  $items['custom_block.list'] = array(
+    'link_title' => 'Custom block library',
+    'parent' => 'block.admin.structure',
+    'description' => 'Manage custom blocks.',
+  );
 
   return $links;
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
index 1f4d86f..af9b359 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
@@ -29,6 +29,10 @@ public function getOptions(Request $request) {
     if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') {
       $options['query']['destination'] = 'admin/structure/block/custom-blocks';
     }
+    // Adds a destination on custom block listing.
+    if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'custom_block.list') {
+      $options['query']['destination'] = 'admin/structure/block/custom-blocks';
+    }
     return $options;
   }
 
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 7593adb..82cb852 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/block/custom_block/tests/modules/custom_block_test/custom_block_test.module b/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
index 7186098..8c53053 100644
--- a/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
+++ b/core/modules/block/custom_block/tests/modules/custom_block_test/custom_block_test.module
@@ -66,17 +66,3 @@ function custom_block_test_custom_block_insert(CustomBlock $custom_block) {
     throw new Exception('Test exception for rollback.');
   }
 }
-
-/**
- * Implements hook_menu().
- */
-function custom_block_test_menu() {
-  $items = array();
-  // Add a block-view callback.
-  $items['custom-block/%custom_block'] = array(
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(1),
-    'route_name' => 'custom_block_test.custom_block_view',
-  );
-  return $items;
-}
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index acfa539..b7a8cc7 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -163,28 +163,6 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
 }
 
 /**
- * Implements hook_menu().
- */
-function book_menu() {
-  $items['admin/structure/book'] = array(
-    'title' => 'Books',
-    'description' => "Manage your site's book outlines.",
-    'route_name' => 'book.admin',
-  );
-  $items['book'] = array(
-    'title' => 'Books',
-    'route_name' => 'book.render',
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  $items['node/%node/outline/remove'] = array(
-    'title' => 'Remove from outline',
-    'route_name' => 'book.remove',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function book_menu_link_defaults() {
diff --git a/core/modules/book/lib/Drupal/book/BookManager.php b/core/modules/book/lib/Drupal/book/BookManager.php
index 601717b..1522922 100644
--- a/core/modules/book/lib/Drupal/book/BookManager.php
+++ b/core/modules/book/lib/Drupal/book/BookManager.php
@@ -866,7 +866,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/comment/comment.module b/core/modules/comment/comment.module
index 0cbe24c..bfdbb2b 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -178,28 +178,6 @@ function comment_theme() {
 }
 
 /**
- * Implements hook_menu().
- */
-function comment_menu() {
-  $items['admin/structure/comments'] = array(
-    'title' => 'Comment forms',
-    'description' => 'Manage fields and displays settings for comment forms.',
-    'route_name' => 'comment.bundle_list',
-  );
-  $items['admin/structure/comments/manage/%'] = array(
-    'title' => 'Comment form',
-    'route_name' => 'comment.bundle',
-  );
-  $items['admin/content/comment'] = array(
-    'title' => 'Comments',
-    'description' => 'List and edit site comments and the comment approval queue.',
-    'route_name' => 'comment.admin',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function comment_menu_link_defaults() {
@@ -220,12 +198,12 @@ function comment_menu_link_defaults() {
 }
 
 /**
- * Implements hook_menu_alter().
+ * Implements hook_menu_link_defaults_alter()
  */
-function comment_menu_alter(&$items) {
-  if (isset($items['admin/content'])) {
+function comment_menu_links_defaults_alter(&$links) {
+  if (isset($links['node.admin.content'])) {
     // Add comments to the description for admin/content if any.
-    $items['admin/content']['description'] = 'Administer content and comments.';
+    $links['node.admin.content']['description'] = 'Administer content and comments.';
   }
 }
 
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index 3cb71e6..776a9fc 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -58,19 +58,6 @@ function config_file_download($uri) {
 }
 
 /**
- * Implements hook_menu().
- */
-function config_menu() {
-  $items['admin/config/development/configuration'] = array(
-    'title' => 'Configuration management',
-    'description' => 'Import, export, or synchronize your site configuration.',
-    'route_name' => 'config.sync',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function config_menu_link_defaults() {
diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module
index 51e406f..77826e0 100644
--- a/core/modules/config/tests/config_test/config_test.module
+++ b/core/modules/config/tests/config_test/config_test.module
@@ -11,32 +11,6 @@
 require_once dirname(__FILE__) . '/config_test.hooks.inc';
 
 /**
- * Implements hook_menu().
- */
-function config_test_menu() {
-  $items['admin/structure/config_test'] = array(
-    'title' => 'Test configuration',
-    'route_name' => 'config_test.list_page',
-  );
-  $items['admin/structure/config_test/manage/%config_test'] = array(
-    'route_name' => 'config_test.entity',
-  );
-  $items['admin/structure/config_test/manage/%config_test/delete'] = array(
-    'title' => 'Delete',
-    'route_name' => 'config_test.entity_delete',
-  );
-  $items['admin/structure/config_test/manage/%config_test/enable'] = array(
-    'title' => 'Enable',
-    'route_name' => 'config_test.entity_enable',
-  );
-  $items['admin/structure/config_test/manage/%config_test/disable'] = array(
-    'title' => 'Disable',
-    'route_name' => 'config_test.entity_disable',
-  );
-  return $items;
-}
-
-/**
  * Loads a ConfigTest object.
  *
  * @param string $id
diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module
index 077e0cd..2204689 100644
--- a/core/modules/config_translation/config_translation.module
+++ b/core/modules/config_translation/config_translation.module
@@ -32,20 +32,6 @@ function config_translation_help($path) {
 }
 
 /**
- * Implements hook_menu().
- */
-function config_translation_menu() {
-  $items = array();
-  $items['admin/config/regional/config-translation'] = array(
-    'title' => 'Configuration translation',
-    'description' => 'Translate the configuration.',
-    'route_name' => 'config_translation.mapper_list',
-    'weight' => 30,
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function config_translation_menu_link_defaults() {
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index bd9454f..6b41139 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -52,34 +52,6 @@ function contact_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function contact_menu() {
-  $items['admin/structure/contact'] = array(
-    'title' => 'Contact form categories',
-    'description' => 'Create a system contact form and set up categories for the form to use.',
-    'route_name' => 'contact.category_list',
-  );
-  $items['admin/structure/contact/manage/%contact_category'] = array(
-    'title' => 'Edit contact category',
-    'route_name' => 'contact.category_edit',
-  );
-
-  $items['contact'] = array(
-    'title' => 'Contact',
-    'route_name' => 'contact.site_page',
-    'menu_name' => 'footer',
-    'type' => MENU_SUGGESTED_ITEM,
-  );
-  $items['contact/%contact_category'] = array(
-    'title' => 'Contact category form',
-    'route_name' => 'contact.site_page_category',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function contact_menu_link_defaults() {
@@ -255,7 +227,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 19e4ea6..57321b8 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -182,72 +182,12 @@ 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().
  *
  * @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_alter(array &$items) {
-  // Clarify where translation settings are located.
-  $items['admin/config/regional/content-language']['title'] = 'Content language and translation';
-  $items['admin/config/regional/content-language']['description'] = 'Configure language and translation support for content.';
-
   // Check that the declared menu base paths are actually valid.
   foreach (\Drupal::entityManager()->getDefinitions() as $entity_type_id => $entity_type) {
     if (content_translation_enabled($entity_type_id)) {
@@ -977,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();
   }
 }
 
@@ -1045,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 c753114..09afe8c 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/dblog/dblog.module b/core/modules/dblog/dblog.module
index 4060d63..cd8e2c0 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -37,42 +37,6 @@ function dblog_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function dblog_menu() {
-  $items['admin/reports/dblog'] = array(
-    'title' => 'Recent log messages',
-    'description' => 'View events that have recently been logged.',
-    'route_name' => 'dblog.overview',
-    'weight' => -1,
-  );
-  $items['admin/reports/page-not-found'] = array(
-    'title' => "Top 'page not found' errors",
-    'description' => "View 'page not found' errors (404s).",
-    'route_name' => 'dblog.page_not_found',
-  );
-  $items['admin/reports/access-denied'] = array(
-    'title' => "Top 'access denied' errors",
-    'description' => "View 'access denied' errors (403s).",
-    'route_name' => 'dblog.access_denied',
-  );
-  $items['admin/reports/event/%'] = array(
-    'title' => 'Details',
-    'route_name' => 'dblog.event',
-  );
-
-  if (\Drupal::moduleHandler()->moduleExists('search')) {
-    $items['admin/reports/search'] = array(
-      'title' => 'Top search phrases',
-      'description' => 'View most popular search phrases.',
-      'route_name' => 'dblog.search',
-    );
-  }
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function dblog_menu_link_defaults() {
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index f1a9840..9266911 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -39,19 +39,11 @@ function editor_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu_alter().
+ * Implements hook_menu_link_defaults_alter().
  *
  * Rewrites the menu entries for filter module that relate to the configuration
  * of text editors.
  */
-function editor_menu_alter(&$items) {
-  $items['admin/config/content/formats']['title'] = 'Text formats and editors';
-  $items['admin/config/content/formats']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
-}
-
-/**
- * Implements hook_menu_link_defaults_alter().
- */
 function editor_menu_link_defaults_alter(array &$links) {
   $links['filter.admin.formats']['link_title'] = 'Text formats and editors';
   $links['filter.admin.formats']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index 4816d0b..f921fcf 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -45,57 +45,6 @@ function entity_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function entity_menu() {
-  $items = array();
-
-  $items['admin/structure/display-modes'] = array(
-    'title' => 'Display modes',
-    'description' => 'Configure what displays are available for your content and forms.',
-    'route_name' => 'entity.display_mode',
-  );
-
-  // View modes.
-  $items['admin/structure/display-modes/view'] = array(
-    'title' => 'View modes',
-    'description' => 'Manage custom view modes.',
-    'route_name' => 'entity.view_mode_list',
-  );
-  $items['admin/structure/display-modes/view/add'] = array(
-    'title' => 'Add view mode',
-    'route_name' => 'entity.view_mode_add',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-  $items['admin/structure/display-modes/view/add/%'] = array(
-    'route_name' => 'entity.view_mode_add_type',
-  );
-  $items['admin/structure/display-modes/view/manage/%/delete'] = array(
-    'route_name' => 'entity.view_mode_delete',
-  );
-
-  // Form modes.
-  $items['admin/structure/display-modes/form'] = array(
-    'title' => 'Form modes',
-    'description' => 'Manage custom form modes.',
-    'route_name' => 'entity.form_mode_list',
-  );
-  $items['admin/structure/display-modes/form/add'] = array(
-    'title' => 'Add form mode',
-    'route_name' => 'entity.form_mode_add',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-  $items['admin/structure/display-modes/form/add/%'] = array(
-    'route_name' => 'entity.form_mode_add_type',
-  );
-  $items['admin/structure/display-modes/form/manage/%/delete'] = array(
-    'route_name' => 'entity.form_mode_delete',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function entity_menu_link_defaults() {
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index c386131..5ece040 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -37,19 +37,6 @@ function field_test_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function field_test_menu() {
-  $items = array();
-  $items['test-entity/nested/%entity_test/%entity_test'] = array(
-    'title' => 'Nested entity form',
-    'route_name' => 'field_test.entity_nested_form',
-  );
-
-  return $items;
-}
-
-/**
  * Store and retrieve keyed data for later verification by unit tests.
  *
  * This function is a simple in-memory key-value store with the
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 08c1cf6..4279bb3 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -53,20 +53,6 @@ function field_ui_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function field_ui_menu() {
-  $items['admin/reports/fields'] = array(
-    'title' => 'Field list',
-    'description' => 'Overview of fields on all entity types.',
-    'route_name' => 'field_ui.list',
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function field_ui_menu_link_defaults() {
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index ca50030..2b09ea7 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -95,36 +95,6 @@ function filter_element_info() {
 }
 
 /**
- * Implements hook_menu().
- */
-function filter_menu() {
-  $items['filter/tips'] = array(
-    'title' => 'Compose tips',
-    'type' => MENU_SUGGESTED_ITEM,
-    'route_name' => 'filter.tips_all',
-  );
-  $items['filter/tips/%'] = array(
-    'title' => 'Compose tips',
-    'route_name' => 'filter.tips',
-  );
-  $items['admin/config/content/formats'] = array(
-    'title' => 'Text formats',
-    'description' => 'Configure how content input by users is filtered, including allowed HTML tags. Also allows enabling of module-provided filters.',
-    'route_name' => 'filter.admin_overview',
-  );
-  $items['admin/config/content/formats/manage/%'] = array(
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-    'route_name' => 'filter.format_edit',
-  );
-  $items['admin/config/content/formats/manage/%/disable'] = array(
-    'title' => 'Disable text format',
-    'route_name' => 'filter.admin_disable',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function filter_menu_link_defaults() {
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 2843782..b1bb1ea 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -95,40 +95,6 @@ function forum_theme() {
 }
 
 /**
- * Implements hook_menu().
- */
-function forum_menu() {
-  $items['forum'] = array(
-    'title' => 'Forums',
-    'route_name' => 'forum.index',
-  );
-  $items['forum/%forum'] = array(
-    'title' => 'Forums',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(1),
-    'route_name' => 'forum.page',
-  );
-  $items['admin/structure/forum'] = array(
-    'title' => 'Forums',
-    'description' => 'Control forum hierarchy settings.',
-    'route_name' => 'forum.overview',
-  );
-  $items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
-    'title' => 'Edit container',
-    'route_name' => 'forum.edit_container',
-  );
-  $items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
-    'title' => 'Edit forum',
-    'route_name' => 'forum.edit_forum',
-  );
-  $items['admin/structure/forum/delete/forum/%taxonomy_term'] = array(
-    'title' => 'Delete forum',
-    'route_name' => 'forum.delete',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function forum_menu_link_defaults() {
diff --git a/core/modules/help/help.module b/core/modules/help/help.module
index 6d07405..89e0f31 100644
--- a/core/modules/help/help.module
+++ b/core/modules/help/help.module
@@ -6,25 +6,6 @@
  */
 
 /**
- * Implements hook_menu().
- */
-function help_menu() {
-  $items['admin/help'] = array(
-    'title' => 'Help',
-    'description' => 'Reference for usage, configuration, and modules.',
-    'route_name' => 'help.main',
-    'weight' => 9,
-  );
-
-  $items['admin/help/%'] = array(
-    'route_name' => 'help.page',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function help_menu_link_defaults() {
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 4d9c5f8..c1420c1 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -84,41 +84,6 @@ function image_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function image_menu() {
-  $items = array();
-
-  $items['admin/config/media/image-styles'] = array(
-    'title' => 'Image styles',
-    'description' => 'Configure styles that can be used for resizing or adjusting images on display.',
-    'route_name' => 'image.style_list',
-  );
-  $items['admin/config/media/image-styles/manage/%image_style'] = array(
-    'title' => 'Edit style',
-    'description' => 'Configure an image style.',
-    'route_name' => 'image.style_edit',
-  );
-  $items['admin/config/media/image-styles/manage/%/effects/%'] = array(
-    'title' => 'Edit image effect',
-    'description' => 'Edit an existing effect within a style.',
-    'route_name' => 'image.effect_edit_form',
-  );
-  $items['admin/config/media/image-styles/manage/%image_style/effects/%/delete'] = array(
-    'title' => 'Delete image effect',
-    'description' => 'Delete an existing effect from a style.',
-    'route_name' => 'image.effect_delete',
-  );
-  $items['admin/config/media/image-styles/manage/%/add/%'] = array(
-    'title' => 'Add image effect',
-    'description' => 'Add a new effect to a style.',
-    'route_name' => 'image.effect_add_form',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function image_menu_link_defaults() {
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 83356b7..9d23058 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -69,29 +69,6 @@ function language_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function language_menu() {
-  // Base language management and configuration.
-  $items['admin/config/regional/language'] = array(
-    'title' => 'Languages',
-    'description' => 'Configure languages for content and the user interface.',
-    'route_name' => 'language.admin_overview',
-    'weight' => 0,
-  );
-
-  // Content language settings.
-  $items['admin/config/regional/content-language'] = array(
-    'title' => 'Content language',
-    'description' => 'Configure language support for content.',
-    'route_name' => 'language.content_settings_page',
-    'weight' => 10,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function language_menu_link_defaults() {
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index 89376c8..89832f3 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -111,7 +111,7 @@ function testUILanguageNegotiation() {
 
     // We will look for this string in the admin/config screen to see if the
     // corresponding translated string is shown.
-    $default_string = 'Configure languages for content and the user interface';
+    $default_string = 'Hide descriptions';
 
     // First visit this page to make sure our target string is searchable.
     $this->drupalGet('admin/config');
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index a4727d4..105f44e 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -168,27 +168,6 @@ function locale_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function locale_menu() {
-  // Translation functionality.
-  $items['admin/config/regional/translate'] = array(
-    'title' => 'User interface translation',
-    'description' => 'Translate the built-in user interface.',
-    'route_name' => 'locale.translate_page',
-    'weight' => 15,
-  );
-
-  $items['admin/reports/translations'] = array(
-    'title' => 'Available translation updates',
-    'route_name' => 'locale.translate_status',
-    'description' => 'Get a status report about available interface translations for your installed modules and themes.',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function locale_menu_link_defaults() {
diff --git a/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php b/core/modules/menu/lib/Drupal/menu/Form/MenuDeleteForm.php
index 57e45c1..709c71b 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 9a7d93b..a027efb 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
@@ -234,8 +234,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;
@@ -260,10 +258,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 c161592..037fc62 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/menu.module b/core/modules/menu/menu.module
index 3259353..15e02ab 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -63,36 +63,6 @@ function menu_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function menu_menu() {
-  $items['admin/structure/menu'] = array(
-    'title' => 'Menus',
-    'description' => 'Add new menus to your site, edit existing menus, and rename and reorganize menu links.',
-    'route_name' => 'menu.overview_page',
-  );
-  $items['admin/structure/menu/manage/%menu'] = array(
-    'title' => 'Edit menu',
-    'route_name' => 'menu.menu_edit',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(4),
-  );
-  $items['admin/structure/menu/item/%menu_link/edit'] = array(
-    'title' => 'Edit menu link',
-    'route_name' => 'menu.link_edit',
-  );
-  $items['admin/structure/menu/item/%menu_link/reset'] = array(
-    'title' => 'Reset menu link',
-    'route_name' => 'menu.link_reset',
-  );
-  $items['admin/structure/menu/item/%menu_link/delete'] = array(
-    'title' => 'Delete menu link',
-    'route_name' => 'menu.link_delete',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function menu_menu_link_defaults() {
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 d244a71..ee9d0b8 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.
@@ -26,13 +20,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.
    *
    * @var bool
@@ -40,35 +27,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}
    */
   public function create(array $values = array()) {
@@ -81,29 +39,6 @@ public function create(array $values = array()) {
   }
 
   /**
-   * {@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().
    */
   public function save(EntityInterface $entity) {
@@ -218,8 +153,7 @@ public function loadModuleAdminTasks() {
       ->condition('base.link_path', 'admin/%', 'LIKE')
       ->condition('base.hidden', 0, '>=')
       ->condition('base.module', 'system')
-      ->condition('m.number_parts', 1, '>')
-      ->condition('m.page_callback', 'system_admin_menu_block_page', '<>');
+      ->condition('base.route_name', 'system.admin', '<>');
     $ids = $query->execute()->fetchCol(1);
 
     return $this->loadMultiple($ids);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 5bef612..a38d788 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -937,53 +937,6 @@ function _node_revision_access(NodeInterface $node, $op = 'view', $account = NUL
 }
 
 /**
- * Implements hook_menu().
- */
-function node_menu() {
-  $items['admin/content'] = array(
-    'title' => 'Content',
-    'description' => 'Find and manage content.',
-    'route_name' => 'node.content_overview',
-    'weight' => -10,
-  );
-
-  $items['admin/structure/types'] = array(
-    'title' => 'Content types',
-    'description' => 'Manage content types, including default status, front page promotion, comment settings, etc.',
-    'route_name' => 'node.overview_types',
-  );
-  $items['node/add'] = array(
-    'title' => 'Add content',
-    'route_name' => 'node.add_page',
-  );
-  $items['node/add/%node_type'] = array(
-    'description callback' => 'node_type_get_description',
-    'description arguments' => array(2),
-    'route_name' => 'node.add',
-  );
-  $items['node/%node'] = array(
-    'title callback' => 'node_page_title',
-    'title arguments' => array(1),
-    // The controller also sets the #title in case the routes' title is
-    // overridden by a menu link.
-    'route_name' => 'node.view',
-  );
-  $items['node/%node/revisions/%node_revision/view'] = array(
-    'title' => 'Revisions',
-    'route_name' => 'node.revision_show',
-  );
-  $items['node/%node/revisions/%node_revision/revert'] = array(
-    'title' => 'Revert to earlier revision',
-    'route_name' => 'node.revision_revert_confirm',
-  );
-  $items['node/%node/revisions/%node_revision/delete'] = array(
-    'title' => 'Delete earlier revision',
-    'route_name' => 'node.revision_delete_confirm',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function node_menu_link_defaults() {
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
index f084a9c..5468547 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/path/path.module b/core/modules/path/path.module
index 3c9f611..10816ee 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -54,28 +54,6 @@ function path_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function path_menu() {
-  $items['admin/config/search/path'] = array(
-    'title' => 'URL aliases',
-    'description' => "Change your site's URL paths by aliasing them.",
-    'route_name' => 'path.admin_overview',
-    'weight' => -5,
-  );
-  $items['admin/config/search/path/edit/%path'] = array(
-    'title' => 'Edit alias',
-    'route_name' => 'path.admin_edit',
-  );
-  $items['admin/config/search/path/delete/%path'] = array(
-    'title' => 'Delete alias',
-    'route_name' => 'path.delete',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function path_menu_link_defaults() {
diff --git a/core/modules/picture/picture.module b/core/modules/picture/picture.module
index ae676c9..f7aecac 100644
--- a/core/modules/picture/picture.module
+++ b/core/modules/picture/picture.module
@@ -46,30 +46,6 @@ function picture_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function picture_menu() {
-  $items = array();
-
-  $items['admin/config/media/picturemapping'] = array(
-    'title' => 'Picture Mappings',
-    'description' => 'Manage picture mappings',
-    'weight' => 10,
-    'route_name' => 'picture.mapping_page',
-  );
-  $items['admin/config/media/picturemapping/%picture_mapping'] = array(
-    'title' => 'Edit picture mapping',
-    'route_name' => 'picture.mapping_page_edit',
-  );
-  $items['admin/config/media/picturemapping/%picture_mapping/duplicate'] = array(
-    'title' => 'Duplicate picture mapping',
-    'route_name' => 'picture.mapping_page_duplicate',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function picture_menu_link_defaults() {
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 600dc83..e60d020 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -139,30 +139,6 @@ function search_preprocess_block(&$variables) {
 }
 
 /**
- * Implements hook_menu().
- */
-function search_menu() {
-  $items['search'] = array(
-    'title' => 'Search',
-    'type' => MENU_SUGGESTED_ITEM,
-    'route_name' => 'search.view',
-  );
-  $items['admin/config/search/settings'] = array(
-    'title' => 'Search settings',
-    'description' => 'Configure relevance settings for search and other indexing options.',
-    'route_name' => 'search.settings',
-    'weight' => -10,
-  );
-  $items['admin/config/search/settings/reindex'] = array(
-    'title' => 'Clear index',
-    'route_name' => 'search.reindex_confirm',
-    'type' => MENU_VISIBLE_IN_BREADCRUMB,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function search_menu_link_defaults() {
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 5631745..a97b447 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -62,33 +62,6 @@ function shortcut_permission() {
 }
 
 /**
- * Implements hook_menu().
- */
-function shortcut_menu() {
-  $items['admin/config/user-interface/shortcut'] = array(
-    'title' => 'Shortcuts',
-    'description' => 'Add and modify shortcut sets.',
-    'route_name' => 'shortcut.set_admin',
-  );
-  $items['admin/config/user-interface/shortcut/manage/%shortcut_set'] = array(
-    'title' => 'Edit shortcuts',
-    'route_name' => 'shortcut.set_customize',
-    'title callback' => 'entity_page_label',
-    'title arguments' => array(5),
-  );
-  $items['admin/config/user-interface/shortcut/link/%shortcut'] = array(
-    'title' => 'Edit shortcut',
-    'route_name' => 'shortcut.link_edit',
-  );
-  $items['admin/config/user-interface/shortcut/link/%shortcut/delete'] = array(
-    'title' => 'Delete shortcut',
-    'route_name' => 'shortcut.link_delete',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function shortcut_menu_link_defaults() {
@@ -389,7 +362,6 @@ function shortcut_preprocess_page(&$variables) {
   // shortcuts and if the page's actual content is being shown (for example,
   // we do not want to display it on "access denied" or "page not found"
   // pages).
-
   // Load the router item corresponding to the current page.
   $request = \Drupal::request();
   $item = array();
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 9795455..93babb7 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/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 99ca601..f7e375a 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -30,24 +30,6 @@ function simpletest_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function simpletest_menu() {
-  $items['admin/config/development/testing'] = array(
-    'title' => 'Testing',
-    'description' => 'Run tests against Drupal core and your modules. These tests help assure that your site code is working as designed.',
-    'route_name' => 'simpletest.test_form',
-    'weight' => -5,
-  );
-  $items['admin/config/development/testing/results/%'] = array(
-    'title' => 'Test result',
-    'description' => 'View result of tests.',
-    'route_name' => 'simpletest.result_form',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function simpletest_menu_link_defaults() {
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index 5f3a4af..8dc09d2 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -79,19 +79,6 @@ function statistics_node_links_alter(array &$node_links, NodeInterface $entity,
 }
 
 /**
- * Implements hook_menu().
- */
-function statistics_menu() {
-  $items['admin/config/system/statistics'] = array(
-    'title' => 'Statistics',
-    'description' => 'Control details about what and how your site logs content statistics.',
-    'route_name' => 'statistics.settings',
-    'weight' => -15,
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function statistics_menu_link_defaults() {
diff --git a/core/modules/system/lib/Drupal/system/Controller/AdminController.php b/core/modules/system/lib/Drupal/system/Controller/AdminController.php
index 6a7bbc0..f1e231f 100644
--- a/core/modules/system/lib/Drupal/system/Controller/AdminController.php
+++ b/core/modules/system/lib/Drupal/system/Controller/AdminController.php
@@ -36,7 +36,7 @@ public function index() {
         // Sort links by title.
         uasort($admin_tasks, 'drupal_sort_title');
         // Move 'Configure permissions' links to the bottom of each section.
-        $permission_key = "admin/people/permissions#module-$module";
+        $permission_key = "user.admin.people.permissions.$module";
         if (isset($admin_tasks[$permission_key])) {
           $permission_task = $admin_tasks[$permission_key];
           unset($admin_tasks[$permission_key]);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
index cc8c4e0..52fa21b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Menu;
 
+use Drupal\locale\TranslationString;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -260,4 +261,24 @@ public function testRouterIntegration() {
     $this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
   }
 
+  /**
+   * Tests uninstall a module providing default links.
+   */
+  public function testModuleUninstalledMenuLinks() {
+    \Drupal::moduleHandler()->install(array('menu_test'));
+    \Drupal::service('router.builder')->rebuild();
+    menu_link_rebuild_defaults();
+    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
+    $menu_links = \Drupal::entityManager()->getStorageController('menu_link')->loadMultiple($result);
+    $this->assertEqual(count($menu_links), 1);
+    $menu_link = reset($menu_links);
+    $this->assertEqual($menu_link->machine_name, 'menu_test');
+
+    // Uninstall the module and ensure the menu link got removed.
+    \Drupal::moduleHandler()->uninstall(array('menu_test'));
+    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
+    $menu_links = \Drupal::entityManager()->getStorageController('menu_link')->loadMultiple($result);
+    $this->assertEqual(count($menu_links), 0);
+  }
+
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
deleted file mode 100644
index 418c451..0000000
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\Tests\Menu\MenuRouterRebuildTest.
- */
-
-namespace Drupal\system\Tests\Menu;
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\Core\Language\Language;
-
-/**
- * Tests menu_router_rebuild().
- */
-class MenuRouterRebuildTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('locale', 'menu_test');
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getInfo() {
-    return array(
-      'name' => 'Menu router rebuild',
-      'description' => 'Tests menu_router_rebuild().',
-      'group' => 'Menu',
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  function setUp() {
-    parent::setUp();
-
-    $language = new Language(array('id' => 'nl'));
-    language_save($language);
-  }
-
-  /**
-   * Tests configuration context when rebuilding the menu router table.
-   */
-  public function testMenuRouterRebuildContext() {
-    // Enter a language context before rebuilding the menu router tables.
-    \Drupal::configFactory()->setLanguage(language_load('nl'));
-    menu_router_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'));
-    $menu_item = reset($menu_items);
-    $this->assertTrue($menu_item['link_title'] == 'English', 'Config context overrides are ignored when rebuilding menu router items.');
-  }
-
-}
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 f631d6f..476d006 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();
   }
@@ -113,16 +112,6 @@ protected function doTestTitleMenuCallback() {
   }
 
   /**
-   * Tests menu item descriptions.
-   */
-  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>'));
-  }
-
-  /**
    * Tests for menu_link_maintain().
    */
   protected function doTestMenuLinkMaintain() {
@@ -169,7 +158,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 e02c9c4..0000000
--- 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 df10877..974208f 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 d692718..bc80cb5 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/Path/PathUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
index faaa158..64a92ea 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/PathUnitTestBase.php
@@ -20,7 +20,7 @@ public function setUp() {
     $this->fixtures = new UrlAliasFixtures();
     // The alias whitelist expects that the menu path roots are set by a
     // menu router rebuild.
-    \Drupal::state()->set('menu_path_roots', array('user', 'admin'));
+    \Drupal::state()->set('router.path_roots', array('user', 'admin'));
   }
 
   public function tearDown() {
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 060303a..d70bb18 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;
 
@@ -38,10 +39,12 @@ public function testPermissionAccess() {
     $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();
+    $path .= 'invalid';
+    $request = RequestHelper::duplicate(\Drupal::request(), '/' . $path);
+    $request->attributes->set('_system_path', $path);
     $route = \Drupal::service('router.route_provider')->getRouteByName('router_test.7');
     try {
-      menu_item_route_access($route, $path . 'invalid', $map);
+      menu_item_route_access($route, $request);
       $exception = FALSE;
     }
     catch (ResourceNotFoundException $e) {
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 900a4fa..bb21bb1 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/AdminTest.php
@@ -48,19 +48,6 @@ function setUp() {
    * Tests output on administrative listing pages.
    */
   function testAdminPages() {
-    // Go to Administration.
-    $this->drupalGet('admin');
-
-    // 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']);
-      }
-    }
-
     // For each administrative listing page on which the Locale module appears,
     // verify that there are links to the module's primary configuration pages,
     // but no links to its individual sub-configuration pages. Also verify that
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 6cdef50..3f3c1c2 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -30,12 +30,7 @@ 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.
+      // Rebuild the menu.
       \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 cd5919c..ddaa382 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -500,94 +500,6 @@ function hook_menu_link_defaults_alter(&$links) {
 }
 
 /**
- * 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.
  *
  * This hook is invoked by menu_local_tasks(). The system-determined tabs and
@@ -1543,11 +1455,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 5e32a6b..0e9a21a 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -715,161 +715,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 71d0679..394379d 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -624,206 +624,6 @@ function system_element_info() {
 }
 
 /**
- * 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().
  */
 function system_menu_link_defaults() {
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 ba8b273..b97f966 100644
--- a/core/modules/system/tests/modules/batch_test/batch_test.module
+++ b/core/modules/system/tests/modules/batch_test/batch_test.module
@@ -6,20 +6,6 @@
  */
 
 /**
- * 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.
  *
  * @see batch_test_simple_form_submit()
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 c1d42bf..04d7ce1 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -240,30 +240,6 @@ function entity_test_permission() {
 }
 
 /**
- * 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().
  */
 function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
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 30dffdc..d718848 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.module
+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -8,147 +8,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().
  */
 function menu_test_menu_link_defaults() {
@@ -158,26 +17,6 @@ function menu_test_menu_link_defaults() {
     'route_name' => 'menu_test.menu_name_test',
     'menu_name' => menu_test_menu_name(),
   );
-  // This item uses SystemController::systemAdminMenuBlockPage() to list child
-  // items.
-  $items['menu_test.menu_callback_description'] = array(
-    'link_title' => 'Menu item title',
-    'description' => 'Menu item description parent',
-    'route_name' => 'menu_test.callback_description',
-  );
-  // This item tests the description key.
-  $items['menu_test.menu_callback_description.description-plain'] = array(
-    'link_title' => 'Menu item with a regular description',
-    'description' => 'Menu item description text',
-    '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',
@@ -338,36 +177,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.
  *
  * @return string
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 637be3c..9680e0f 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
@@ -21,29 +21,6 @@ menu_test.login_callback:
   requirements:
     _access: 'TRUE'
 
-menu_test.callback_description:
-  path: '/menu_callback_description'
-  defaults:
-    _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
-  requirements:
-    _access: 'TRUE'
-
-menu_test.callback_description_plain:
-  path: '/menu_callback_description/description-plain'
-  defaults:
-    _title: 'Menu item with a regular description'
-    _content: '\Drupal\menu_test\Controller\MenuTestController::menuTestCallback'
-  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/system/tests/modules/module_test/module_test.module b/core/modules/system/tests/modules/module_test/module_test.module
index e0ae6f4..b1372c0 100644
--- a/core/modules/system/tests/modules/module_test/module_test.module
+++ b/core/modules/system/tests/modules/module_test/module_test.module
@@ -69,25 +69,6 @@ function module_test_hook_info() {
 }
 
 /**
- * Implements hook_menu().
- */
-function module_test_menu() {
-  $items['module-test/hook-dynamic-loading-invoke'] = array(
-    'title' => 'Test hook dynamic loading (invoke)',
-    'route_name' => 'module_test.dynamic_invoke',
-  );
-  $items['module-test/hook-dynamic-loading-invoke-all'] = array(
-    'title' => 'Test hook dynamic loading (invoke_all)',
-    'route_name' => 'module_test.dynamic_invoke_all',
-  );
-  $items['module-test/class-loading'] = array(
-    'title' => 'Test loading a class from another module',
-    'route_name' => 'module_test.class_loading',
-  );
-  return $items;
-}
-
-/**
  * Page callback for 'hook dynamic loading' test.
  *
  * If the hook is dynamically loaded correctly, the menu callback should
diff --git a/core/modules/system/tests/modules/plugin_test/plugin_test.module b/core/modules/system/tests/modules/plugin_test/plugin_test.module
index 6a33894..147e052 100644
--- a/core/modules/system/tests/modules/plugin_test/plugin_test.module
+++ b/core/modules/system/tests/modules/plugin_test/plugin_test.module
@@ -14,14 +14,3 @@ function plugin_test_plugin_test_alter(&$definitions) {
   }
   $definitions['user_login']['altered_single'] = TRUE;
 }
-
-/**
- * Implements hook_menu().
- */
-function plugin_test_menu() {
-  $items = array();
-  $items['plugin_definition_test'] = array(
-    'route_name' => 'plugin_test.definition',
-  );
-  return $items;
-}
diff --git a/core/modules/system/tests/modules/test_page_test/test_page_test.module b/core/modules/system/tests/modules/test_page_test/test_page_test.module
index 7933a85..93c10c5 100644
--- a/core/modules/system/tests/modules/test_page_test/test_page_test.module
+++ b/core/modules/system/tests/modules/test_page_test/test_page_test.module
@@ -1,18 +1,6 @@
 <?php
 
 /**
- * Implements hook_menu().
- */
-function test_page_test_menu() {
-  $items['test-page'] = array(
-    'title' => 'Test front page',
-    'route_name' => 'test_page_test.test_page',
-  );
-
-  return $items;
-}
-
-/**
  * Page callback: Returns a test page and sets the title.
  *
  * @deprecated Use \Drupal\test_page_test\Controller\TestPageTestController::testPage()
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index 4e1fc13..667ad83 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -64,27 +64,6 @@ function theme_test_system_theme_info() {
 }
 
 /**
- * Implements hook_menu().
- */
-function theme_test_menu() {
-  $items['theme-test/suggestion'] = array(
-    'route_name' => 'theme_test.suggestion',
-    'theme callback' => '_theme_custom_theme',
-    'type' => MENU_CALLBACK,
-  );
-  $items['theme-test/alter'] = array(
-    'theme callback' => '_theme_custom_theme',
-    'route_name' => 'theme_test.alter',
-    'type' => MENU_CALLBACK,
-  );
-  $items['theme-test/function-template-overridden'] = array(
-    'theme callback' => '_theme_custom_theme',
-    'route_name' => 'theme_test.function_template_override',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_preprocess_HOOK() for HTML document templates.
  */
 function theme_test_preprocess_html(&$variables) {
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 3124f63..e51eef8 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -233,33 +233,6 @@ function taxonomy_theme() {
 }
 
 /**
- * Implements hook_menu().
- */
-function taxonomy_menu() {
-  $items['admin/structure/taxonomy'] = array(
-    'title' => 'Taxonomy',
-    'description' => 'Manage tagging, categorization, and classification of your content.',
-    'route_name' => 'taxonomy.vocabulary_list',
-  );
-
-  $items['taxonomy/term/%taxonomy_term'] = array(
-    'title' => 'Taxonomy term',
-    'title callback' => 'taxonomy_term_title',
-    'title arguments' => array(2),
-    'route_name' => 'taxonomy.term_page',
-  );
-  $items['taxonomy/term/%taxonomy_term/feed'] = array(
-    'title' => 'Taxonomy term',
-    'title callback' => 'taxonomy_term_title',
-    'title arguments' => array(2),
-    'route_name' => 'taxonomy.term_feed',
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function taxonomy_menu_link_defaults() {
diff --git a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
index 3ca1039..082a6a7 100644
--- a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
+++ b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarAdminMenuTest.php
@@ -411,6 +411,7 @@ function testLocaleTranslationSubtreesHashCacheClear() {
       'translation' => 'untranslated',
     );
     $this->drupalPostForm('admin/config/regional/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available'));
     $this->assertText($name, 'Search found the string as untranslated.');
 
     // Assume this is the only result.
diff --git a/core/modules/tour/tests/tour_test/tour_test.module b/core/modules/tour/tests/tour_test/tour_test.module
index 0df3e57..3b1ca24 100644
--- a/core/modules/tour/tests/tour_test/tour_test.module
+++ b/core/modules/tour/tests/tour_test/tour_test.module
@@ -18,18 +18,19 @@ function tour_test_admin_paths() {
 }
 
 /**
- * Implements hook_menu().
+ * Implements hook_menu_link_defaults().
  */
-function tour_test_menu() {
-  $items['tour-test-1'] = array(
+function hook_menu_link_defaults() {
+  $links['tour_test.1'] = array(
     'route_name' => 'tour_test.1',
-    'title' => 'Tour test 1'
+    'link_title' => 'Tour test 1'
   );
-  $items['tour-test-2/subpath'] = array(
+  $links['tour_test.2'] = array(
     'route_name' => 'tour_test.2',
-    'title' => 'Tour test 2'
+    'link_title' => 'Tour test 2'
   );
-  return $items;
+
+  return $links;
 }
 
 /**
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 027c285..c2dea88 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -145,22 +145,6 @@ function update_page_build() {
 }
 
 /**
- * Implements hook_menu().
- */
-function update_menu() {
-  $items = array();
-
-  $items['admin/reports/updates'] = array(
-    'title' => 'Available updates',
-    'description' => 'Get a status report about available updates for your installed modules and themes.',
-    'route_name' => 'update.status',
-    'weight' => -50,
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function update_menu_link_defaults() {
diff --git a/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RegisterAccessCheck.php
index e234afb..eff984b 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 0a42c91..3c478f7 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 134804f..aefc9d3 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 4ff18d3..130fac4 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -682,122 +682,6 @@ function theme_username($variables) {
 }
 
 /**
- * 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().
- */
-function user_menu() {
-  // Registration and login pages.
-  $items['user'] = array(
-    'title' => 'User account',
-    'title callback' => 'user_menu_title',
-    'weight' => -10,
-    'route_name' => 'user.page',
-    'menu_name' => 'account',
-  );
-
-  // Since menu_get_ancestors() does not support multiple placeholders in a row,
-  // this MENU_CALLBACK cannot be removed yet.
-  $items['user/reset/%/%/%'] = array(
-    'title' => 'Reset password',
-    'route_name' => 'user.reset',
-    'type' => MENU_CALLBACK,
-  );
-
-  $items['user/logout'] = array(
-    'title' => 'Log out',
-    'route_name' => 'user.logout',
-    'weight' => 10,
-    'menu_name' => 'account',
-  );
-
-  // User listing pages.
-  $items['admin/people'] = array(
-    'title' => 'People',
-    'description' => 'Manage user accounts, roles, and permissions.',
-    'route_name' => 'user.admin_account',
-    'position' => 'left',
-    'weight' => -4,
-  );
-
-  // Permissions and role forms.
-  $items['admin/people/permissions'] = array(
-    'title' => 'Permissions',
-    'description' => 'Determine access to features by selecting permissions for roles.',
-    'route_name' => 'user.admin_permissions',
-    'type' => MENU_SIBLING_LOCAL_TASK,
-  );
-
-  $items['admin/people/roles/manage/%user_role'] = array(
-    'title' => 'Edit role',
-    'route_name' => 'user.role_edit',
-  );
-
-  // Administration pages.
-  $items['admin/config/people'] = array(
-    'title' => 'People',
-    'description' => 'Configure user accounts.',
-    'position' => 'left',
-    'weight' => -20,
-    'route_name' => 'user.admin_index',
-  );
-
-  $items['admin/config/people/accounts'] = array(
-    'title' => 'Account settings',
-    'description' => 'Configure default behavior of users, including registration requirements, e-mails, and fields.',
-    'weight' => -10,
-    'route_name' => 'user.account_settings',
-  );
-
-  $items['user/%user'] = array(
-    'title' => 'My account',
-    'title callback' => 'user_page_title',
-    'title arguments' => array(1),
-    'route_name' => 'user.view',
-  );
-  $items['user/%user/cancel'] = array(
-    'route_name' => 'user.cancel',
-  );
-  $items['user/%user/cancel/confirm/%/%'] = array(
-    'title' => 'Confirm account cancellation',
-    'route_name' => 'user.cancel_confirm',
-  );
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function user_menu_link_defaults() {
@@ -895,81 +779,6 @@ function user_admin_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.
  *
  * @param $name
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index 72d2725..47626aa 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -2386,21 +2386,6 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
   }
 
   /**
-   * If this display creates a page with a menu item, implement it here.
-   *
-   * @param array $callbacks
-   *   An array of already existing menu items provided by drupal.
-   *
-   * @return array
-   *   The menu router items registers for this display.
-   *
-   * @see hook_menu()
-   */
-  public function executeHookMenu($callbacks) {
-    return array();
-  }
-
-  /**
    * Render this display.
    */
   public function render() {
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 7b22ce9..ac2f706 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
@@ -328,121 +328,6 @@ public function executeHookMenuLinkDefaults(array &$existing_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().
    */
   public function 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 75c7b65..079e003 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 1ef7ca8..a9ff2cf 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 0c0c517..f239773 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 bd024e2..7c710e3 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 ad0a627..ae18750 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 5a62bed..8d7e1f5 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 5867c98..48ad3f2 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 807880a..5efa290 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 6fa98d2..17131c4 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -1512,28 +1512,6 @@ public function attachDisplays() {
   }
 
   /**
-   * 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.
    *
    * @param string $display_id
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index f6fbd2e..1d1f1b5 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -271,51 +271,6 @@ function views_permission() {
 }
 
 /**
- * Implement hook_menu_alter().
- */
-function views_menu_alter(&$callbacks) {
-  $our_paths = array();
-  $views = views_get_applicable_views('uses_hook_menu');
-  foreach ($views as $data) {
-    list($view, $display_id) = $data;
-    $result = $view->executeHookMenu($display_id, $callbacks);
-    if (is_array($result)) {
-      // The menu system doesn't support having two otherwise
-      // identical paths with different placeholders.  So we
-      // want to remove the existing items from the menu whose
-      // paths would conflict with ours.
-
-      // First, we must find any existing menu items that may
-      // conflict.  We use a regular expression because we don't
-      // know what placeholders they might use.  Note that we
-      // first construct the regex itself by replacing %views_arg
-      // in the display path, then we use this constructed regex
-      // (which will be something like '#^(foo/%[^/]*/bar)$#') to
-      // search through the existing paths.
-      $regex = '#^(' . preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) . ')$#';
-      $matches = preg_grep($regex, array_keys($callbacks));
-
-      // Remove any conflicting items that were found.
-      foreach ($matches as $path) {
-        // Don't remove the paths we just added!
-        if (!isset($our_paths[$path])) {
-          unset($callbacks[$path]);
-        }
-      }
-      foreach ($result as $path => $item) {
-        if (!isset($callbacks[$path])) {
-          // Add a new item, possibly replacing (and thus effectively
-          // overriding) one that we removed above.
-          $callbacks[$path] = $item;
-        }
-        $our_paths[$path] = TRUE;
-      }
-    }
-    $view->destroy();
-  }
-}
-
-/**
  * Implements hook_menu_link_defaults_alter().
  */
 function views_menu_link_defaults_alter(array &$links) {
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 246f4ba..1d4a598 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -38,29 +38,6 @@ function views_ui_help($path, $arg) {
 }
 
 /**
- * Implements hook_menu().
- */
-function views_ui_menu() {
-  $items = array();
-
-  // Top-level Views module pages (not tied to a particular View).
-  $items['admin/structure/views'] = array(
-    'title' => 'Views',
-    'description' => 'Manage customized lists of content.',
-    'route_name' => 'views_ui.list',
-  );
-
-  // A page in the Reports section to show usage of plugins in all views.
-  $items['admin/reports/views-plugins'] = array(
-    'title' => 'Views plugins',
-    'description' => 'Overview of plugins used in all views.',
-    'route_name' => 'views_ui.reports_plugins',
-  );
-
-  return $items;
-}
-
-/**
  * Implements hook_menu_link_defaults().
  */
 function views_ui_menu_link_defaults() {
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php
new file mode 100644
index 0000000..87e722b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/PathRootsSubscriberTest.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\EventSubscriber\PathRootsSubscriberTest.
+ */
+
+namespace Drupal\Tests\Core\EventSubscriber;
+
+use Drupal\Core\EventSubscriber\PathRootsSubscriber;
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Tests Drupal\Core\EventSubscriber\PathRootsSubscriber.
+ *
+ * @group Drupal
+ * @group Routing
+ *
+ * @coversDefaultClass \Drupal\Core\EventSubscriber\PathRootsSubscriber
+ */
+class PathRootsSubscriberTest extends UnitTestCase {
+
+  /**
+   * The mocked state.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $state;
+
+  /**
+   * The tested path root subscriber.
+   *
+   * @var \Drupal\Core\EventSubscriber\PathRootsSubscriber
+   */
+  protected $pathRootsSubscriber;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Drupal\Core\EventSubscriber\PathRootsSubscriber',
+      'description' => '',
+      'group' => 'Routing'
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->state = $this->getMock('Drupal\Core\KeyValueStore\StateInterface');
+    $this->pathRootsSubscriber = new PathRootsSubscriber($this->state);
+  }
+
+  /**
+   * Tests altering and finished event.
+   *
+   * @covers ::onRouteAlter()
+   * @covers ::onRouteFinished()
+   */
+  public function testSubscribing() {
+    $route_collection = new RouteCollection();
+    $route_collection->add('test_route1', new Route('/test/bar'));
+    $route_collection->add('test_route2', new Route('/test/baz'));
+    $route_collection->add('test_route3', new Route('/test2/bar/baz'));
+
+    $event = new RouteBuildEvent($route_collection, 'provider');
+    $this->pathRootsSubscriber->onRouteAlter($event);
+
+    $route_collection = new RouteCollection();
+    $route_collection->add('test_route4', new Route('/test1/bar'));
+    $route_collection->add('test_route5', new Route('/test2/baz'));
+    $route_collection->add('test_route6', new Route('/test2/bar/baz'));
+
+    $event = new RouteBuildEvent($route_collection, 'provider');
+    $this->pathRootsSubscriber->onRouteAlter($event);
+
+    $this->state->expects($this->once())
+      ->method('set')
+      ->with('router.path_roots', array('test', 'test2', 'test1'));
+
+    $this->pathRootsSubscriber->onRouteFinished();
+  }
+
+}
