diff --git a/core/modules/book/book.install b/core/modules/book/book.install
index fb8c225..efb2816 100644
--- a/core/modules/book/book.install
+++ b/core/modules/book/book.install
@@ -23,34 +23,114 @@ function book_schema() {
   $schema['book'] = array(
   'description' => 'Stores book outline information. Uniquely connects each node in the outline to a link in {menu_links}',
     'fields' => array(
-      'mlid' => array(
+      'nid' => array(
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'description' => "The book page's {menu_links}.mlid.",
+        'description' => "The book page's {node}.nid.",
       ),
-      'nid' => array(
+      'bid' => array(
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'description' => "The book page's {node}.nid.",
+        'description' => "The book ID is the {book}.nid of the top-level page.",
       ),
-      'bid' => array(
+      'pid' => array(
+        'description' => 'The parent ID (pid) is the id of the node above in the hierarchy, or zero if the node is at the top level in its menu.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'has_children' => array(
+        'description' => 'Flag indicating whether any nodes have this node as a parent (1 = children exist, 0 = no children).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small',
+      ),
+      'weight' => array(
+        'description' => 'Weight among book entries in the same book at the same depth.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'depth' => array(
+        'description' => 'The depth relative to the top level. A link with pid == 0 will have depth == 1.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small',
+      ),
+      'p1' => array(
+        'description' => 'The first nid in the materialized path. If N = depth, then pN must equal the nid. If depth > 1 then p(N-1) must equal the pid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p2' => array(
+        'description' => 'The second nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p3' => array(
+        'description' => 'The third nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p4' => array(
+        'description' => 'The fourth nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p5' => array(
+        'description' => 'The fifth nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p6' => array(
+        'description' => 'The sixth nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p7' => array(
+        'description' => 'The seventh nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p8' => array(
+        'description' => 'The eighth nid in the materialized path. See p1.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'p9' => array(
+        'description' => 'The ninth nid in the materialized path. See p1.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'description' => "The book ID is the {book}.nid of the top-level page.",
       ),
     ),
-    'primary key' => array('mlid'),
-    'unique keys' => array(
-      'nid' => array('nid'),
-    ),
+    'primary key' => array('nid'),
     'indexes' => array(
-      'bid' => array('bid'),
+      'book_parents' => array('bid', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
     ),
   );
 
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 282aa92..6a9abd4 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -42,29 +42,6 @@ function book_help($path, $arg) {
 }
 
 /**
- * Implements hook_entity_bundle_info().
- */
-function book_entity_bundle_info() {
-  $bundles['menu_link']['book-toc'] = array(
-    'label' => t('Book'),
-    'translatable' => FALSE,
-  );
-  return $bundles;
-}
-
-/**
- * Implements hook_TYPE_load().
- */
-function book_menu_link_load($entities) {
-  foreach ($entities as $entity) {
-    // Change the bundle of menu links related to a book.
-    if (strpos($entity->menu_name, 'book-toc-') === 0) {
-      $entity->bundle = 'book-toc';
-    }
-  }
-}
-
-/**
  * Implements hook_theme().
  */
 function book_theme() {
@@ -139,7 +116,7 @@ function book_node_view_link(NodeInterface $node, $view_mode) {
         $links['book_add_child'] = array(
           'title' => t('Add child page'),
           'href' => 'node/add/' . $child_type,
-          'query' => array('parent' => $node->book['mlid']),
+          'query' => array('parent' => $node->id()),
         );
       }
 
@@ -331,7 +308,7 @@ function book_pick_book_nojs_submit($form, &$form_state) {
  *   The rendered parent page select element.
  */
 function book_form_update($form, $form_state) {
-  return $form['book']['plid'];
+  return $form['book']['pid'];
 }
 
 /**
@@ -350,10 +327,10 @@ function book_form_update($form, $form_state) {
 function book_get_flat_menu($book_link) {
   $flat = &drupal_static(__FUNCTION__, array());
 
-  if (!isset($flat[$book_link['mlid']])) {
+  if (!isset($flat[$book_link['nid']])) {
     // Call menu_tree_all_data() to take advantage of the menu system's caching.
     $tree = menu_tree_all_data($book_link['menu_name'], $book_link, $book_link['depth'] + 1);
-    $flat[$book_link['mlid']] = array();
+    $flat[$book_link['nid']] = array();
     _book_flatten_menu($tree, $flat[$book_link['mlid']]);
   }
 
@@ -519,20 +496,6 @@ function book_node_view(EntityInterface $node, EntityDisplay $display, $view_mod
 }
 
 /**
- * Implements hook_page_alter().
- *
- * Adds the book menu to the list of menus used to build the active trail when
- * viewing a book page.
- */
-function book_page_alter(&$page) {
-  if (($node = menu_get_object()) && !empty($node->book['bid'])) {
-    $active_menus = menu_get_active_menu_names();
-    $active_menus[] = $node->book['menu_name'];
-    menu_set_active_menu_names($active_menus);
-  }
-}
-
-/**
  * Implements hook_node_presave().
  */
 function book_node_presave(EntityInterface $node) {
@@ -542,7 +505,7 @@ function book_node_presave(EntityInterface $node) {
   }
   // Make sure a new node gets a new menu link.
   if ($node->isNew()) {
-    $node->book['mlid'] = NULL;
+    $node->book['nid'] = NULL;
   }
 }
 
@@ -557,7 +520,6 @@ function book_node_insert(EntityInterface $node) {
       $node->book['bid'] = $node->id();
     }
     $node->book['nid'] = $node->id();
-    $node->book['menu_name'] = $book_manager->createMenuName($node->book['bid']);
     $book_manager->updateOutline($node);
   }
 }
@@ -573,7 +535,6 @@ function book_node_update(EntityInterface $node) {
       $node->book['bid'] = $node->id();
     }
     $node->book['nid'] = $node->id();
-    $node->book['menu_name'] = $book_manager->createMenuName($node->book['bid']);
     $book_manager->updateOutline($node);
   }
 }
@@ -585,8 +546,8 @@ function book_node_predelete(EntityInterface $node) {
   if (!empty($node->book['bid'])) {
     if ($node->id() == $node->book['bid']) {
       // Handle deletion of a top-level post.
-      $result = db_query("SELECT b.nid FROM {menu_links} ml INNER JOIN {book} b on b.mlid = ml.mlid WHERE ml.plid = :plid", array(
-        ':plid' => $node->book['mlid']
+      $result = db_query("SELECT b.nid FROM {book} b WHERE b.nid = :nid", array(
+        ':nid' => $node->book['nid']
       ));
       foreach ($result as $child) {
         $child_node = node_load($child->id());
@@ -594,9 +555,8 @@ function book_node_predelete(EntityInterface $node) {
         \Drupal::service('book.manager')->updateOutline($child_node);
       }
     }
-    menu_link_delete($node->book['mlid']);
     db_delete('book')
-      ->condition('mlid', $node->book['mlid'])
+      ->condition('nid', $node->book['nid'])
       ->execute();
     drupal_static_reset('book_get_books');
   }
@@ -621,8 +581,7 @@ function book_node_prepare_form(NodeInterface $node, $form_display, $operation,
 
       if ($parent && $parent['access']) {
         $node->book['bid'] = $parent['bid'];
-        $node->book['plid'] = $parent['mlid'];
-        $node->book['menu_name'] = $parent['menu_name'];
+        $node->book['pid'] = $parent['nid'];
       }
     }
     // Set defaults.
@@ -706,11 +665,11 @@ function template_preprocess_book_navigation(&$variables) {
   // Provide extra variables for themers. Not needed by default.
   $variables['book_id'] = $book_link['bid'];
   $variables['book_title'] = check_plain($book_link['link_title']);
-  $variables['book_url'] = 'node/' . $book_link['bid'];
+  $variables['book_url'] = \Drupal::url('node.view', array('node' => $book_link['bid']));
   $variables['current_depth'] = $book_link['depth'];
   $variables['tree'] = '';
 
-  if ($book_link['mlid']) {
+  if ($book_link['nid']) {
     $variables['tree'] = book_children($book_link);
 
     if ($prev = book_prev($book_link)) {
@@ -872,7 +831,7 @@ function book_menu_subtree_data($link) {
   $tree = &drupal_static(__FUNCTION__, array());
 
   // Generate a cache ID (cid) specific for this $menu_name and $link.
-  $cid = 'links:' . $link['menu_name'] . ':subtree-cid:' . $link['mlid'];
+  $cid = 'links:' . $link['bid'] . ':subtree-cid:' . $link['nid'];
 
   if (!isset($tree[$cid])) {
     $cache = cache('menu')->get($cid);
@@ -889,13 +848,9 @@ function book_menu_subtree_data($link) {
 
     // If the subtree data was not in the cache, $data will be NULL.
     if (!isset($data)) {
-      $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
-      $query->join('menu_router', 'm', 'm.path = ml.router_path');
-      $query->join('book', 'b', 'ml.mlid = b.mlid');
+      $query = db_select('book', 'b', array('fetch' => PDO::FETCH_ASSOC));
       $query->fields('b');
-      $query->fields('m', array('load_functions', 'to_arg_functions', 'access_callback', 'access_arguments', 'page_callback', 'page_arguments', 'title', 'title_callback', 'title_arguments', 'type'));
-      $query->fields('ml');
-      $query->condition('menu_name', $link['menu_name']);
+      $query->condition('b.bid', $link['bid']);
       for ($i = 1; $i <= MENU_MAX_DEPTH && $link["p$i"]; ++$i) {
         $query->condition("p$i", $link["p$i"]);
       }
diff --git a/core/modules/book/lib/Drupal/book/BookManager.php b/core/modules/book/lib/Drupal/book/BookManager.php
index d154c46..16764e7 100644
--- a/core/modules/book/lib/Drupal/book/BookManager.php
+++ b/core/modules/book/lib/Drupal/book/BookManager.php
@@ -89,22 +89,20 @@ protected function loadBooks() {
 
     if ($nids) {
       $query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC));
-      $query->join('menu_links', 'ml', 'b.mlid = ml.mlid');
       $query->fields('b');
-      $query->fields('ml');
       $query->condition('b.nid', $nids);
-      $query->orderBy('ml.weight');
-      $query->orderBy('ml.link_title');
       $query->addTag('node_access');
       $query->addMetaData('base_table', 'book');
       $book_links = $query->execute();
 
       $nodes = $this->entityManager->getStorageController('node')->loadMultiple($nids);
+      // @todo: Sort by weight and translated title.
 
+      // @todo: use route name for links, not system path.
       foreach ($book_links as $link) {
         $nid = $link['nid'];
         if (isset($nodes[$nid]) && $nodes[$nid]->status) {
-          $link['href'] = $link['link_path'];
+          $link['href'] = 'node/' . $nid;
           $link['options'] = unserialize($link['options']);
           $link['title'] = $nodes[$nid]->label();
           $link['type'] = $nodes[$nid]->bundle();
@@ -126,15 +124,11 @@ protected function loadBooks() {
   public function getLinkDefaults($nid) {
     return array(
       'original_bid' => 0,
-      'menu_name' => '',
       'nid' => $nid,
       'bid' => 0,
-      'router_path' => 'node/%',
-      'plid' => 0,
-      'mlid' => 0,
+      'pid' => 0,
       'has_children' => 0,
       'weight' => 0,
-      'module' => 'book',
       'options' => array(),
     );
   }
@@ -187,14 +181,14 @@ public function addFormElements(array $form, array &$form_state, NodeInterface $
       ),
       '#tree' => TRUE,
     );
-    foreach (array('menu_name', 'mlid', 'nid', 'router_path', 'has_children', 'options', 'module', 'original_bid', 'parent_depth_limit') as $key) {
+    foreach (array('nid', 'has_children', 'options', 'module', 'original_bid', 'parent_depth_limit') as $key) {
       $form['book'][$key] = array(
         '#type' => 'value',
         '#value' => $node->book[$key],
       );
     }
 
-    $form['book']['plid'] = $this->addParentSelectFormElements($node->book);
+    $form['book']['pid'] = $this->addParentSelectFormElements($node->book);
 
     // @see \Drupal\book\Form\BookAdminEditForm::bookAdminTableTree(). The
     // weight may be larger than 15.
@@ -222,7 +216,7 @@ public function addFormElements(array $form, array &$form_state, NodeInterface $
       // The node can become a new book, if it is not one already.
       $options = array($nid => $this->t('- Create a new book -')) + $options;
     }
-    if (!$node->book['mlid']) {
+    if (!$node->book['bid']) {
       // The node is not currently in the hierarchy.
       $options = array(0 => $this->t('- None -')) + $options;
     }
@@ -280,19 +274,17 @@ public function updateOutline(NodeInterface $node) {
     if (empty($node->book['bid'])) {
       return FALSE;
     }
-    $new = empty($node->book['mlid']);
+    $new = empty($node->book['nid']);
 
-    $node->book['link_path'] = 'node/' . $node->id();
-    $node->book['link_title'] = $node->label();
     $node->book['parent_mismatch'] = FALSE; // The normal case.
 
     if ($node->book['bid'] == $node->id()) {
-      $node->book['plid'] = 0;
+      $node->book['pid'] = 0;
       $node->book['menu_name'] = $this->createMenuName($node->id());
     }
     else {
       // Check in case the parent is not is this book; the book takes precedence.
-      if (!empty($node->book['plid'])) {
+      if (!empty($node->book['pid'])) {
         $parent = $this->connection->query("SELECT * FROM {book} WHERE mlid = :mlid", array(
           ':mlid' => $node->book['plid'],
         ))->fetchAssoc();
@@ -313,7 +305,6 @@ public function updateOutline(NodeInterface $node) {
         $this->connection->insert('book')
           ->fields(array(
             'nid' => $node->id(),
-            'mlid' => $node->book['mlid'],
             'bid' => $node->book['bid'],
           ))
           ->execute();
@@ -344,36 +335,23 @@ protected function t($string, array $args = array(), array $options = array()) {
   }
 
   /**
-   * Generates the corresponding menu name from a book ID.
-   *
-   * @param $id
-   *   The book ID for which to make a menu name.
-   *
-   * @return
-   *   The menu name.
-   */
-  public function createMenuName($id) {
-    return 'book-toc-' . $id;
-  }
-
-  /**
    * Updates the book ID of a page and its children when it moves to a new book.
    *
    * @param array $book_link
    *   A fully loaded menu link that is part of the book hierarchy.
    */
   public function updateID($book_link) {
-    $query = $this->connection->select('menu_links');
-    $query->addField('menu_links', 'mlid');
+    $query = $this->connection->select('book');
+    $query->addField('book', 'nid');
     for ($i = 1; $i <= MENU_MAX_DEPTH && $book_link["p$i"]; $i++) {
       $query->condition("p$i", $book_link["p$i"]);
     }
-    $mlids = $query->execute()->fetchCol();
+    $nids = $query->execute()->fetchCol();
 
     if ($mlids) {
       $this->connection->update('book')
         ->fields(array('bid' => $book_link['bid']))
-        ->condition('mlid', $mlids, 'IN')
+        ->condition('nid', $nids, 'IN')
         ->execute();
     }
   }
@@ -460,8 +438,8 @@ protected function recurseTableOfContents(array $tree, $indent, array &$toc, arr
         break;
       }
 
-      if (!in_array($data['link']['mlid'], $exclude)) {
-        $toc[$data['link']['mlid']] = $indent . ' ' . truncate_utf8($data['link']['title'], 30, TRUE, TRUE);
+      if (!in_array($data['link']['nid'], $exclude)) {
+        $toc[$data['link']['nid']] = $indent . ' ' . truncate_utf8($data['link']['title'], 30, TRUE, TRUE);
         if ($data['below']) {
           $this->recurseTableOfContents($data['below'], $indent . '--', $toc, $exclude, $depth_limit);
         }
