diff --git a/core/modules/menu/lib/Drupal/menu/Access/DeleteMenuAccessCheck.php b/core/modules/menu/lib/Drupal/menu/Access/DeleteMenuAccessCheck.php
deleted file mode 100644
index e8fb6f2..0000000
--- a/core/modules/menu/lib/Drupal/menu/Access/DeleteMenuAccessCheck.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu\Access\DeleteMenuAccessCheck.
- */
-
-namespace Drupal\menu\Access;
-
-use Drupal\Core\Access\StaticAccessCheckInterface;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Access check for menu delete routes.
- */
-class DeleteMenuAccessCheck implements StaticAccessCheckInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function appliesTo() {
-    return array('_access_menu_delete_menu');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(Route $route, Request $request) {
-    if (user_access('administer menu') && $menu = $request->attributes->get('menu')) {
-      // System-defined menus may not be deleted.
-      $system_menus = menu_list_system_menus();
-      return !isset($system_menus[$menu->id()]);
-    }
-    return FALSE;
-  }
-}
diff --git a/core/modules/menu/lib/Drupal/menu/Controller/MenuController.php b/core/modules/menu/lib/Drupal/menu/Controller/MenuController.php
new file mode 100644
index 0000000..f707dfb
--- /dev/null
+++ b/core/modules/menu/lib/Drupal/menu/Controller/MenuController.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu\Controller\MenuController.
+ */
+
+namespace Drupal\menu\Controller;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\menu_link\MenuLinkStorageControllerInterface;
+use Drupal\system\MenuInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Returns responses for Menu routes.
+ */
+class MenuController implements ControllerInterface {
+
+  /**
+   * The menu link storage.
+   *
+   * @var \Drupal\menu_link\MenuLinkStorageControllerInterface
+   */
+  protected $menuLinkStorage;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a new MenuController.
+   *
+   * @param \Drupal\menu_link\MenuLinkStorageControllerInterface $menu_link_storage
+   *   The storage controller.
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(MenuLinkStorageControllerInterface $menu_link_storage, EntityManager $entity_manager) {
+    $this->menuLinkStorage = $menu_link_storage;
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.entity')->getStorageController('menu_link'),
+      $container->get('plugin.manager.entity')
+    );
+  }
+
+  /**
+   * Gets all the available menus and menu items as a JavaScript array.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request of the page.
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
+   *   The available menu and menu items.
+   */
+  public function getParentOptions(Request $request) {
+    $available_menus = array();
+    if ($menus = $request->request->get('menus')) {
+      foreach ($menus as $menu) {
+        $available_menus[$menu] = $menu;
+      }
+    }
+    $options = _menu_get_options(menu_get_menus(), $available_menus, array('mlid' => 0));
+
+    return new JsonResponse($options);
+  }
+
+  /**
+   * Provides the menu link submission form.
+   *
+   * @param \Drupal\system\MenuInterface $menu
+   *   An entity representing a custom menu.
+   *
+   * @return array
+   *   Returns the menu link submission form.
+   */
+  public function addLink(MenuInterface $menu) {
+    // @todo Remove this when https://drupal.org/node/1981644 is in.
+    drupal_set_title(t('Add menu link'));
+    $menu_link = $this->menuLinkStorage->create(array(
+      'mlid' => 0,
+      'plid' => 0,
+      'menu_name' => $menu->id(),
+    ));
+    return $this->entityManager->getForm($menu_link);
+  }
+
+}
diff --git a/core/modules/menu/lib/Drupal/menu/MenuFormController.php b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
index a709d2e..bedb08b 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
@@ -2,14 +2,18 @@
 
 /**
  * @file
- * Contains Drupal\menu\MenuFormController.
+ * Contains \Drupal\menu\MenuFormController.
  */
 
 namespace Drupal\menu;
 
+use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityControllerInterface;
 use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\Language;
+use Drupal\menu_link\MenuLinkStorageControllerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -18,12 +22,65 @@
 class MenuFormController extends EntityFormController implements EntityControllerInterface {
 
   /**
+   * The factory for entity queries.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryFactory
+   */
+  protected $entityQueryFactory;
+
+  /**
+   * The menu link storage controller.
+   *
+   * @var \Drupal\menu_link\MenuLinkStorageControllerInterface
+   */
+  protected $menuLinkStorage;
+
+  /**
+   * The overview tree form.
+   *
+   * @var array
+   */
+  protected $overviewTreeForm = array('#tree' => TRUE);
+
+  /**
+   * Constructs a MenuFormController object.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks on.
+   * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
+   *   The factory for entity queries.
+   * @param \Drupal\menu_link\MenuLinkStorageControllerInterface $menu_link_storage
+   *   The menu link storage controller.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, QueryFactory $entity_query_factory, MenuLinkStorageControllerInterface $menu_link_storage) {
+    parent::__construct($module_handler);
+
+    $this->entityQueryFactory = $entity_query_factory;
+    $this->menuLinkStorage = $menu_link_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $container->get('module_handler'),
+      $container->get('entity.query'),
+      $container->get('plugin.manager.entity')->getStorageController('menu_link')
+    );
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
    */
   public function form(array $form, array &$form_state) {
     $menu = $this->entity;
+
+    if ($this->operation == 'edit') {
+      drupal_set_title(t('Edit menu %label', array('%label' => $menu->label())), PASS_THROUGH);
+    }
+
     $system_menus = menu_list_system_menus();
-    $form_state['menu'] = &$menu;
 
     $form['label'] = array(
       '#type' => 'textfield',
@@ -39,7 +96,7 @@ public function form(array $form, array &$form_state) {
       '#description' => t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
       '#field_prefix' => $menu->isNew() ? 'menu-' : '',
       '#machine_name' => array(
-        'exists' => 'menu_edit_menu_name_exists',
+        'exists' => array($this, 'menuNameExists'),
         'source' => array('label'),
         'replace_pattern' => '[^a-z0-9-]+',
         'replace' => '-',
@@ -83,17 +140,37 @@ public function form(array $form, array &$form_state) {
       // within forms, but does not allow to handle the form section's submission
       // equally separated yet. Therefore, we use a $form_state key to point to
       // the parents of the form section.
-      // @see menu_overview_form_submit()
+      // @see self::submitOverviewForm()
       $form_state['menu_overview_form_parents'] = array('links');
       $form['links'] = array();
-      $form['links'] = menu_overview_form($form['links'], $form_state);
+      $form['links'] = $this->buildOverviewForm($form['links'], $form_state);
     }
 
     return parent::form($form, $form_state);
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   * Returns whether a menu name already exists.
+   *
+   * @param string $value
+   *   The name of the menu.
+   *
+   * @return bool
+   *   Returns TRUE if the menu already exists, FALSE otherwise.
+   */
+  public function menuNameExists($value) {
+    // Check first to see if a menu with this ID exists.
+    if ($this->entityQueryFactory->get('menu')->condition('id', $value)->range(0, 1)->count()->execute()) {
+      return TRUE;
+    }
+
+    // Check for a link assigned to this menu. 'menu-' is added to the menu name
+    // to avoid name-space conflicts.
+    return $this->entityQueryFactory->get('menu_link')->condition('menu_name', 'menu-' . $value)->range(0, 1)->count()->execute();
+  }
+
+  /**
+   * {@inheritdoc}
    */
   protected function actions(array $form, array &$form_state) {
     $actions = parent::actions($form, $form_state);
@@ -142,14 +219,14 @@ public function languageConfigurationSubmit(array &$form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   * {@inheritdoc}
    */
   public function save(array $form, array &$form_state) {
     $menu = $this->entity;
     $system_menus = menu_list_system_menus();
 
     if (!$menu->isNew() || isset($system_menus[$menu->id()])) {
-      menu_overview_form_submit($form, $form_state);
+      $this->submitOverviewForm($form, $form_state);
     }
 
     $status = $menu->save();
@@ -168,11 +245,201 @@ public function save(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityFormController::delete().
+   * {@inheritdoc}
    */
   public function delete(array $form, array &$form_state) {
-    $menu = $this->entity;
-    $form_state['redirect'] = 'admin/structure/menu/manage/' . $menu->id() . '/delete';
+    $form_state['redirect'] = 'admin/structure/menu/manage/' . $this->entity->id() . '/delete';
+  }
+
+  /**
+   * Form constructor to edit an entire menu tree at once.
+   *
+   * Shows for one menu the menu links accessible to the current user and
+   * relevant operations.
+   *
+   * This form constructor can be integrated as a section into another form. It
+   * relies on the following keys in $form_state:
+   * - menu: A loaded menu definition, as returned by menu_load().
+   * - menu_overview_form_parents: An array containing the parent keys to this
+   *   form.
+   * Forms integrating this section should call menu_overview_form_submit() from
+   * 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;
+    $form['#theme'] = 'menu_overview_form';
+    $form_state += array('menu_overview_form_parents' => array());
+
+    $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css');
+
+    $links = array();
+    $query = $this->entityQueryFactory->get('menu_link')
+      ->condition('menu_name', $this->entity->id());
+    for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
+      $query->sort('p' . $i, 'ASC');
+    }
+    $result = $query->execute();
+
+    if (!empty($result)) {
+      $links = $this->menuLinkStorage->loadMultiple($result);
+    }
+
+    $delta = max(count($links), 50);
+    $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;
+    menu_tree_check_access($tree, $node_links);
+    $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')));
+
+    return $form;
+  }
+
+  /**
+   * Recursive helper function for buildOverviewForm().
+   *
+   * @param $tree
+   *   The menu_tree retrieved by menu_tree_data.
+   * @param $delta
+   *   The default number of menu items used in the menu weight selector is 50.
+   *
+   * @return array
+   *   The overview tree form.
+   */
+  protected function buildOverviewTreeForm($tree, $delta) {
+    $form = &$this->overviewTreeForm;
+    foreach ($tree as $data) {
+      $item = $data['link'];
+      // Don't show callbacks; these have $item['hidden'] < 0.
+      if ($item && $item['hidden'] >= 0) {
+        $mlid = 'mlid:' . $item['mlid'];
+        $form[$mlid]['#item'] = $item;
+        $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
+        $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']);
+        if ($item['hidden']) {
+          $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')';
+        }
+        elseif ($item['link_path'] == 'user' && $item['module'] == 'system') {
+          $form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')';
+        }
+
+        $form[$mlid]['hidden'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Enable @title menu link', array('@title' => $item['title'])),
+          '#title_display' => 'invisible',
+          '#default_value' => !$item['hidden'],
+        );
+        $form[$mlid]['weight'] = array(
+          '#type' => 'weight',
+          '#delta' => $delta,
+          '#default_value' => $item['weight'],
+          '#title_display' => 'invisible',
+          '#title' => t('Weight for @title', array('@title' => $item['title'])),
+        );
+        $form[$mlid]['mlid'] = array(
+          '#type' => 'hidden',
+          '#value' => $item['mlid'],
+        );
+        $form[$mlid]['plid'] = array(
+          '#type' => 'hidden',
+          '#default_value' => $item['plid'],
+        );
+        // Build a list of operations.
+        $operations = array();
+        $links = array();
+        $links['edit'] = array(
+          'title' => t('Edit'),
+          'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit',
+        );
+        $operations['edit'] = array('#type' => 'link', '#title' => t('Edit'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit');
+        // Only items created by the menu module can be deleted.
+        if ($item['module'] == 'menu' || $item['updated'] == 1) {
+          $links['delete'] = array(
+            'title' => t('Delete'),
+            'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete',
+          );
+          $operations['delete'] = array('#type' => 'link', '#title' => t('Delete'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete');
+        }
+        // Set the reset column.
+        elseif ($item['module'] == 'system' && $item['customized']) {
+          $links['reset'] = array(
+            'title' => t('Reset'),
+            'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset',
+          );
+          $operations['reset'] = array('#type' => 'link', '#title' => t('Reset'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset');
+        }
+        $form[$mlid]['operations'] = array(
+          '#type' => 'operations',
+          '#links' => $links,
+        );
+      }
+
+      if ($data['below']) {
+        $this->buildOverviewTreeForm($data['below'], $delta);
+      }
+    }
+    return $form;
+  }
+
+  /**
+   * Submit handler for the menu overview form.
+   *
+   * This function takes great care in saving parent items first, then items
+   * underneath them. Saving items in the incorrect order can break the menu tree.
+   */
+  protected function submitOverviewForm(array $complete_form, array &$form_state) {
+    // Form API supports constructing and validating self-contained sections
+    // within forms, but does not allow to handle the form section's submission
+    // equally separated yet. Therefore, we use a $form_state key to point to
+    // the parents of the form section.
+    $parents = $form_state['menu_overview_form_parents'];
+    $input = NestedArray::getValue($form_state['input'], $parents);
+    $form = &NestedArray::getValue($complete_form, $parents);
+
+    // When dealing with saving menu items, the order in which these items are
+    // saved is critical. If a changed child item is saved before its parent,
+    // the child item could be saved with an invalid path past its immediate
+    // parent. To prevent this, save items in the form in the same order they
+    // are sent, ensuring parents are saved first, then their children.
+    // See http://drupal.org/node/181126#comment-632270
+    $order = is_array($input) ? array_flip(array_keys($input)) : array();
+    // Update our original form with the new order.
+    $form = array_intersect_key(array_merge($order, $form), $form);
+
+    $updated_items = array();
+    $fields = array('weight', 'plid');
+    foreach (element_children($form) as $mlid) {
+      if (isset($form[$mlid]['#item'])) {
+        $element = $form[$mlid];
+        // Update any fields that have changed in this menu item.
+        foreach ($fields as $field) {
+          if ($element[$field]['#value'] != $element[$field]['#default_value']) {
+            $element['#item'][$field] = $element[$field]['#value'];
+            $updated_items[$mlid] = $element['#item'];
+          }
+        }
+        // Hidden is a special case, the value needs to be reversed.
+        if ($element['hidden']['#value'] != $element['hidden']['#default_value']) {
+          // Convert to integer rather than boolean due to PDO cast to string.
+          $element['#item']['hidden'] = $element['hidden']['#value'] ? 0 : 1;
+          $updated_items[$mlid] = $element['#item'];
+        }
+      }
+    }
+
+    // Save all our changed items to the database.
+    foreach ($updated_items as $item) {
+      $item['customized'] = 1;
+      $item->save();
+    }
   }
 
 }
diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
index b444f79..1303f43 100644
--- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
+++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php
@@ -188,7 +188,7 @@ function deleteCustomMenu($menu) {
     $this->assertFalse($result, 'All menu links associated to the custom menu were deleted.');
 
     // Make sure there's no delete button on system menus.
-    $this->drupalGet('admin/structure/menu/manage/main/edit');
+    $this->drupalGet('admin/structure/menu/manage/main');
     $this->assertNoRaw('edit-delete', 'The delete button was not found');
 
     // Try to delete the main menu.
@@ -375,7 +375,7 @@ function testSystemMenuRename() {
     $edit = array(
       'label' => $this->randomName(16),
     );
-    $this->drupalPost('admin/structure/menu/manage/main/edit', $edit, t('Save'));
+    $this->drupalPost('admin/structure/menu/manage/main', $edit, t('Save'));
 
     // Make sure menu shows up with new name in block addition.
     $default_theme = variable_get('theme_default', 'stark');
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index 7346712..2fe9455 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -5,254 +5,6 @@
  * Administrative page callbacks for menu module.
  */
 
-use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
-use Drupal\system\Plugin\Core\Entity\Menu;
-use Drupal\Component\Utility\NestedArray;
-use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-
-/**
- * Menu callback which shows an overview page of all the custom menus and their descriptions.
- */
-function menu_overview_page() {
-  return Drupal::entityManager()
-    ->getListController('menu')
-    ->render();
-}
-
-/**
- * Page callback: Presents the menu creation form.
- *
- * @return array
- *   A form array as expected by drupal_render().
- *
- * @see menu_menu()
- */
-function menu_menu_add() {
-  $menu = entity_create('menu', array());
-  return Drupal::entityManager()->getForm($menu);
-}
-
-/**
- * Page callback: Presents the menu edit form.
- *
- * @param \Drupal\system\Plugin\Core\Entity\Menu $menu
- *   The menu to edit.
- *
- * @return array
- *   A form array as expected by drupal_render().
- *
- * @see menu_menu()
- */
-function menu_menu_edit(Menu $menu) {
-  drupal_set_title(t('Edit menu %label', array('%label' => $menu->label())), PASS_THROUGH);
-  return Drupal::entityManager()->getForm($menu);
-}
-
-/**
- * Form constructor to edit an entire menu tree at once.
- *
- * Shows for one menu the menu links accessible to the current user and
- * relevant operations.
- *
- * This form constructor can be integrated as a section into another form. It
- * relies on the following keys in $form_state:
- * - menu: A loaded menu definition, as returned by menu_load().
- * - menu_overview_form_parents: An array containing the parent keys to this
- *   form.
- * Forms integrating this section should call menu_overview_form_submit() from
- * their form submit handler.
- */
-function menu_overview_form($form, &$form_state) {
-  global $menu_admin;
-
-  // Ensure that menu_overview_form_submit() knows the parents of this form
-  // section.
-  $form['#tree'] = TRUE;
-  $form['#theme'] = 'menu_overview_form';
-  $form_state += array('menu_overview_form_parents' => array());
-
-  $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css');
-
-  $links = array();
-  $query = Drupal::entityQuery('menu_link')
-    ->condition('menu_name', $form_state['menu']->id());
-  for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
-    $query->sort('p' . $i, 'ASC');
-  }
-  $result = $query->execute();
-
-  if (!empty($result)) {
-    $links = menu_link_load_multiple($result);
-  }
-
-  $delta = max(count($links), 50);
-  $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;
-  menu_tree_check_access($tree, $node_links);
-  $menu_admin = FALSE;
-
-  // Inline the "Add link" action so it displays right above the table of
-  // links. No access check needed, since this form has the same access
-  // restriction as adding menu items to the menu.
-  $form['inline_actions'] = array(
-    '#prefix' => '<ul class="action-links">',
-    '#suffix' => '</ul>',
-  );
-  $form['inline_actions']['add'] = array(
-    '#theme' => 'menu_local_action',
-    '#link' => array(
-      'href' => 'admin/structure/menu/manage/' . $form_state['menu']->id() . '/add',
-      'title' => t('Add link'),
-    ),
-  );
-  $form = array_merge($form, _menu_overview_tree_form($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/' . $form_state['menu']->id() .'/add')));
-
-  return $form;
-}
-
-/**
- * Recursive helper function for menu_overview_form().
- *
- * @param $tree
- *   The menu_tree retrieved by menu_tree_data.
- * @param $delta
- *   The default number of menu items used in the menu weight selector is 50.
- */
-function _menu_overview_tree_form($tree, $delta = 50) {
-  $form = &drupal_static(__FUNCTION__, array('#tree' => TRUE));
-  foreach ($tree as $data) {
-    $title = '';
-    $item = $data['link'];
-    // Don't show callbacks; these have $item['hidden'] < 0.
-    if ($item && $item['hidden'] >= 0) {
-      $mlid = 'mlid:' . $item['mlid'];
-      $form[$mlid]['#item'] = $item;
-      $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
-      $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']);
-      if ($item['hidden']) {
-        $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')';
-      }
-      elseif ($item['link_path'] == 'user' && $item['module'] == 'system') {
-        $form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')';
-      }
-
-      $form[$mlid]['hidden'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Enable @title menu link', array('@title' => $item['title'])),
-        '#title_display' => 'invisible',
-        '#default_value' => !$item['hidden'],
-      );
-      $form[$mlid]['weight'] = array(
-        '#type' => 'weight',
-        '#delta' => $delta,
-        '#default_value' => $item['weight'],
-        '#title_display' => 'invisible',
-        '#title' => t('Weight for @title', array('@title' => $item['title'])),
-      );
-      $form[$mlid]['mlid'] = array(
-        '#type' => 'hidden',
-        '#value' => $item['mlid'],
-      );
-      $form[$mlid]['plid'] = array(
-        '#type' => 'hidden',
-        '#default_value' => $item['plid'],
-      );
-      // Build a list of operations.
-      $operations = array();
-      $links = array();
-      $links['edit'] = array(
-        'title' => t('Edit'),
-        'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit',
-      );
-      $operations['edit'] = array('#type' => 'link', '#title' => t('Edit'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit');
-      // Only items created by the menu module can be deleted.
-      if ($item['module'] == 'menu' || $item['updated'] == 1) {
-        $links['delete'] = array(
-          'title' => t('Delete'),
-          'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete',
-        );
-        $operations['delete'] = array('#type' => 'link', '#title' => t('Delete'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete');
-      }
-      // Set the reset column.
-      elseif ($item['module'] == 'system' && $item['customized']) {
-        $links['reset'] = array(
-          'title' => t('Reset'),
-          'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset',
-        );
-        $operations['reset'] = array('#type' => 'link', '#title' => t('Reset'), '#href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset');
-      }
-      $form[$mlid]['operations'] = array(
-        '#type' => 'operations',
-        '#links' => $links,
-      );
-    }
-
-    if ($data['below']) {
-      _menu_overview_tree_form($data['below'], $delta);
-    }
-  }
-  return $form;
-}
-
-/**
- * Submit handler for the menu overview form.
- *
- * This function takes great care in saving parent items first, then items
- * underneath them. Saving items in the incorrect order can break the menu tree.
- *
- * @see menu_overview_form()
- */
-function menu_overview_form_submit($complete_form, &$form_state) {
-  // Form API supports constructing and validating self-contained sections
-  // within forms, but does not allow to handle the form section's submission
-  // equally separated yet. Therefore, we use a $form_state key to point to
-  // the parents of the form section.
-  $parents = $form_state['menu_overview_form_parents'];
-  $input = NestedArray::getValue($form_state['input'], $parents);
-  $form = &NestedArray::getValue($complete_form, $parents);
-
-  // When dealing with saving menu items, the order in which these items are
-  // saved is critical. If a changed child item is saved before its parent,
-  // the child item could be saved with an invalid path past its immediate
-  // parent. To prevent this, save items in the form in the same order they
-  // are sent, ensuring parents are saved first, then their children.
-  // See http://drupal.org/node/181126#comment-632270
-  $order = is_array($input) ? array_flip(array_keys($input)) : array();
-  // Update our original form with the new order.
-  $form = array_intersect_key(array_merge($order, $form), $form);
-
-  $updated_items = array();
-  $fields = array('weight', 'plid');
-  foreach (element_children($form) as $mlid) {
-    if (isset($form[$mlid]['#item'])) {
-      $element = $form[$mlid];
-      // Update any fields that have changed in this menu item.
-      foreach ($fields as $field) {
-        if ($element[$field]['#value'] != $element[$field]['#default_value']) {
-          $element['#item'][$field] = $element[$field]['#value'];
-          $updated_items[$mlid] = $element['#item'];
-        }
-      }
-      // Hidden is a special case, the value needs to be reversed.
-      if ($element['hidden']['#value'] != $element['hidden']['#default_value']) {
-        // Convert to integer rather than boolean due to PDO cast to string.
-        $element['#item']['hidden'] = $element['hidden']['#value'] ? 0 : 1;
-        $updated_items[$mlid] = $element['#item'];
-      }
-    }
-  }
-
-  // Save all our changed items to the database.
-  foreach ($updated_items as $item) {
-    $item['customized'] = 1;
-    menu_link_save($item);
-  }
-}
-
 /**
  * Returns HTML for the menu overview form into a table.
  *
@@ -323,69 +75,3 @@ function theme_menu_overview_form($variables) {
   $output .= drupal_render_children($form);
   return $output;
 }
-
-/**
- * Returns whether a menu name already exists.
- *
- * @see menu_edit_menu()
- * @see form_validate_machine_name()
- */
-function menu_edit_menu_name_exists($value) {
-  $custom_exists = entity_load('menu', $value);
-  // 'menu-' is added to the menu name to avoid name-space conflicts.
-  $value = 'menu-' . $value;
-  $link_exists = Drupal::entityQuery('menu_link')->condition('menu_name', $value)->range(0,1)->count()->execute();
-
-  return $custom_exists || $link_exists;
-}
-
-/**
- * Submit function for adding or editing a custom menu.
- */
-function menu_edit_menu_submit($form, &$form_state) {
-  $menu = $form_state['values'];
-  $path = 'admin/structure/menu/manage/';
-  if ($form['#insert']) {
-    // Add 'menu-' to the menu name to help avoid name-space conflicts.
-    $menu['id'] = 'menu-' . $menu['id'];
-    $system_link = entity_load_multiple_by_properties('menu_link', array('link_path' => 'admin/structure/menu', 'module' => 'system'));
-    $system_link = reset($system_link);
-    $menu_link = entity_create('menu_link', array(
-      'link_title' => $menu['label'],
-      'link_path' => $path . $menu['id'],
-      'router_path' => $path . '%',
-      'plid' => $system_link->id(),
-    ));
-    $menu_link->save();
-    menu_save($menu);
-  }
-  else {
-    menu_save($menu);
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => $path . $menu['id']));
-    foreach ($menu_links as $menu_link) {
-      $menu_link->link_title = $menu['label'];
-      $menu_link->save();
-    }
-  }
-  drupal_set_message(t('Your configuration has been saved.'));
-  $form_state['redirect'] = $path . $menu['id'];
-}
-
-/**
- * Menu callback: Provides the menu link submission form.
- *
- * @param \Drupal\system\Plugin\Core\Entity\Menu $menu
- *   An entity representing a custom menu.
- *
- * @return
- *   Returns the menu link submission form.
- */
-function menu_link_add(Menu $menu) {
-  $menu_link = entity_create('menu_link', array(
-    'mlid' => 0,
-    'plid' => 0,
-    'menu_name' => $menu->id(),
-  ));
-  drupal_set_title(t('Add menu link'));
-  return Drupal::entityManager()->getForm($menu_link);
-}
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index df5f602..9d9e85c 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -68,16 +68,7 @@ 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.',
-    'page callback' => 'menu_overview_page',
-    'access callback' => 'user_access',
-    'access arguments' => array('administer menu'),
-    'file' => 'menu.admin.inc',
-  );
-  $items['admin/structure/menu/parents'] = array(
-    'title' => 'Parent menu items',
-    'page callback' => 'menu_parent_options_js',
-    'type' => MENU_CALLBACK,
-    'access arguments' => array('administer menu'),
+    'route_name' => 'menu_overview_page',
   );
   $items['admin/structure/menu/list'] = array(
     'title' => 'List menus',
@@ -85,40 +76,29 @@ function menu_menu() {
   );
   $items['admin/structure/menu/add'] = array(
     'title' => 'Add menu',
-    'page callback' => 'menu_menu_add',
-    'access arguments' => array('administer menu'),
+    'route_name' => 'menu_menu_add',
     'type' => MENU_LOCAL_ACTION,
-    'file' => 'menu.admin.inc',
   );
   $items['admin/structure/menu/settings'] = array(
     'title' => 'Settings',
     'route_name' => 'menu_settings',
-    'access arguments' => array('administer menu'),
     'type' => MENU_LOCAL_TASK,
     'weight' => 100,
   );
   $items['admin/structure/menu/manage/%menu'] = array(
     'title' => 'Edit menu',
-    'page callback' => 'menu_menu_edit',
-    'page arguments' => array(4),
+    'route_name' => 'menu_menu_edit',
     'title callback' => 'entity_page_label',
     'title arguments' => array(4),
-    'access arguments' => array('administer menu'),
-    'file' => 'menu.admin.inc',
   );
-  // Not officially a local action, but displayed as such in
-  // menu_overview_form().
   $items['admin/structure/menu/manage/%menu/add'] = array(
-    'title' => 'Add menu link',
-    'page callback' => 'menu_link_add',
-    'page arguments' => array(4),
-    'access arguments' => array('administer menu'),
-    'file' => 'menu.admin.inc',
+    'title' => 'Add link',
+    'route_name' => 'menu_link_add',
+    'type' => MENU_LOCAL_ACTION,
   );
   $items['admin/structure/menu/manage/%menu/edit'] = array(
     'title' => 'Edit menu',
     'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => -10,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
   );
   $items['admin/structure/menu/manage/%menu/delete'] = array(
@@ -127,9 +107,7 @@ function menu_menu() {
   );
   $items['admin/structure/menu/item/%menu_link/edit'] = array(
     'title' => 'Edit menu link',
-    'page callback' => 'entity_get_form',
-    'page arguments' => array(4),
-    'access arguments' => array('administer menu'),
+    'route_name' => 'menu_link_edit',
   );
   $items['admin/structure/menu/item/%menu_link/reset'] = array(
     'title' => 'Reset menu link',
@@ -150,7 +128,8 @@ function menu_entity_info(&$entity_info) {
   $entity_info['menu']['controllers']['access'] = 'Drupal\menu\MenuAccessController';
   $entity_info['menu']['uri_callback'] = 'menu_uri';
   $entity_info['menu']['controllers']['form'] = array(
-    'default' => 'Drupal\menu\MenuFormController',
+    'add' => 'Drupal\menu\MenuFormController',
+    'edit' => 'Drupal\menu\MenuFormController',
     'delete' => 'Drupal\menu\Form\MenuDeleteForm',
   );
 
@@ -211,7 +190,7 @@ function menu_enable() {
 
   $base_link = entity_create('menu_link', array(
     'menu_name' => $system_link->menu_name,
-    'router_path' => 'admin/structure/menu/manage/%',
+    'router_path' => 'admin/structure/menu/manage/%menu',
     'module' => 'menu',
   ));
 
@@ -221,6 +200,7 @@ function menu_enable() {
     $link->plid = $system_link->id();
     $link->link_title = $menu->label();
     $link->link_path = 'admin/structure/menu/manage/' . $menu->id();
+    $link->route_name = 'menu_menu_edit';
 
     $query = Drupal::entityQuery('menu_link')
       ->condition('link_path', $link->link_path)
@@ -359,23 +339,6 @@ function menu_parent_options(array $menus, MenuLink $menu_link = NULL, $type = N
 }
 
 /**
- * Page callback.
- * Get all the available menus and menu items as a JavaScript array.
- */
-function menu_parent_options_js() {
-  $available_menus = array();
-  $menus = Drupal::request()->request->get('menus');
-  if (count($menus)) {
-    foreach ($menus as $menu) {
-      $available_menus[$menu] = $menu;
-    }
-  }
-  $options = _menu_get_options(menu_get_menus(), $available_menus, array('mlid' => 0));
-
-  return new JsonResponse($options);
-}
-
-/**
  * Helper function to get the items of the given menu.
  */
 function _menu_get_options($menus, $available_menus, $item) {
diff --git a/core/modules/menu/menu.routing.yml b/core/modules/menu/menu.routing.yml
index 62c54f2..d710470 100644
--- a/core/modules/menu/menu.routing.yml
+++ b/core/modules/menu/menu.routing.yml
@@ -5,6 +5,34 @@ menu_settings:
   requirements:
     _permission: 'administer menu'
 
+menu_overview_page:
+  pattern: '/admin/structure/menu'
+  defaults:
+    _entity_list: 'menu'
+  requirements:
+    _permission: 'administer menu'
+
+menu_parent_options_js:
+  pattern: '/admin/structure/menu/parents'
+  defaults:
+    _controller: '\Drupal\menu\Controller\MenuController::getParentOptions'
+  requirements:
+    _permission: 'administer menu'
+
+menu_link_add:
+  pattern: '/admin/structure/menu/manage/{menu}/add'
+  defaults:
+    _content: '\Drupal\menu\Controller\MenuController::addLink'
+  requirements:
+    _permission: 'administer menu'
+
+menu_link_edit:
+  pattern: '/admin/structure/menu/item/{menu_link}/edit'
+  defaults:
+    _entity_form: 'menu_link'
+  requirements:
+    _permission: 'administer menu'
+
 menu_link_reset:
   pattern: 'admin/structure/menu/item/{menu_link}/reset'
   defaults:
@@ -19,9 +47,23 @@ menu_link_delete:
   requirements:
     _access_menu_delete_link: 'TRUE'
 
+menu_menu_add:
+  pattern: '/admin/structure/menu/add'
+  defaults:
+    _entity_form: 'menu.add'
+  requirements:
+    _entity_create_access: 'menu'
+
+menu_menu_edit:
+  pattern: '/admin/structure/menu/manage/{menu}'
+  defaults:
+    _entity_form: 'menu.edit'
+  requirements:
+    _entity_access: 'menu.update'
+
 menu_delete_menu:
   pattern: 'admin/structure/menu/manage/{menu}/delete'
   defaults:
     _entity_form: 'menu.delete'
   requirements:
-    _access_menu_delete_menu: 'TRUE'
+    _entity_access: 'menu.delete'
diff --git a/core/modules/menu/menu.services.yml b/core/modules/menu/menu.services.yml
index f417d6f..f68094f 100644
--- a/core/modules/menu/menu.services.yml
+++ b/core/modules/menu/menu.services.yml
@@ -3,7 +3,3 @@ services:
     class: Drupal\menu\Access\DeleteLinkAccessCheck
     tags:
       - { name: access_check }
-  access_check.menu.delete_menu:
-    class: Drupal\menu\Access\DeleteMenuAccessCheck
-    tags:
-      - { name: access_check }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php
index f8a2177..dd4cee8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/BreadcrumbTest.php
@@ -114,7 +114,6 @@ function testBreadCrumbs() {
       'admin/structure/menu' => t('Menus'),
     );
     $this->assertBreadcrumb('admin/structure/menu/manage/tools', $trail);
-    $this->assertBreadcrumb('admin/structure/menu/manage/tools/edit', $trail);
 
     $mlid_node_add = db_query('SELECT mlid FROM {menu_links} WHERE link_path = :href AND module = :module', array(
       ':href' => 'node/add',
