diff --git a/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php b/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php
index 7b85e8c..d59199d 100644
--- a/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php
+++ b/core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php
@@ -43,6 +43,15 @@ public static function createFromDataType($data_type) {
   }
 
   /**
+   * Returns the field definition.
+   *
+   * @return array
+   */
+  public function getFieldDefinition() {
+    return $this->fieldDefinition;
+  }
+
+  /**
    * Creates a new field item definition.
    *
    * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
index 29fa9bc..c608b87 100644
--- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
+++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Menu;
 
 use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Core\Session\AccountInterface;
 
@@ -45,6 +46,13 @@ class DefaultMenuLinkTreeManipulators {
    protected $queryFactory;
 
   /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
    * Constructs a \Drupal\Core\Menu\DefaultMenuLinkTreeManipulators object.
    *
    * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
@@ -53,11 +61,14 @@ class DefaultMenuLinkTreeManipulators {
    *   The current user.
    * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
    *   The entity query factory.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
    */
-  public function __construct(AccessManagerInterface $access_manager, AccountInterface $account, QueryFactory $query_factory) {
+  public function __construct(AccessManagerInterface $access_manager, AccountInterface $account, QueryFactory $query_factory, EntityManagerInterface $entity_manager) {
     $this->accessManager = $access_manager;
     $this->account = $account;
     $this->queryFactory = $query_factory;
+    $this->entityManager = $entity_manager;
   }
 
   /**
@@ -139,6 +150,49 @@ public function checkNodeAccess(array $tree) {
   }
 
   /**
+   * Load all entities which are part of the menu tree using loadMultiple().
+   *
+   * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
+   *   The menu link tree to manipulate.
+   */
+  public function loadEntities(array &$tree) {
+    $entity_ids = [];
+    $this->collectEntityIds($tree, $entity_ids);
+
+    foreach ($entity_ids as $entity_type => $ids) {
+      $this->entityManager->getStorage($entity_type)->loadMultiple(array_unique($ids));
+    }
+  }
+
+  /**
+   * Collect all entity IDs of all referenced entities.
+   *
+   * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
+   *   The menu link tree to manipulate.
+   * @param array $entity_ids
+   *   The entity IDs keyed by entity type.
+   */
+  protected function collectEntityIds(array &$tree, array &$entity_ids) {
+    foreach ($tree as $key => &$element) {
+      if (isset($element->access)) {
+        continue;
+      }
+      $route_name = $element->link->getRouteName();
+      // Find a better way to extract the entity type.
+      if (strpos($route_name, 'entity.') === 0 && strpos($route_name, '.canonical') !== FALSE) {
+        $entity_type = substr($route_name, 7, -10);
+        $parameters = $element->link->getRouteParameters();
+        if (isset($parameters[$entity_type])) {
+          $entity_ids[$entity_type][] = $parameters[$entity_type];
+        }
+      }
+      if ($element->hasChildren) {
+        $this->collectNodeLinks($element->subtree, $entity_ids);
+      }
+    }
+  }
+
+  /**
    * Collects the node links in the menu tree.
    *
    * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
diff --git a/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php b/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php
index e5a1264..1aa812f 100644
--- a/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php
+++ b/core/lib/Drupal/Core/Menu/MenuParentFormSelector.php
@@ -68,6 +68,7 @@ public function getParentSelectOptions($id = '', array $menus = NULL) {
       $tree = $this->menuLinkTree->load($menu_name, $parameters);
       $manipulators = array(
         array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+        array('callable' => 'menu.default_tree_manipulators:loadEntities'),
         array('callable' => 'menu.default_tree_manipulators:checkAccess'),
         array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
       );
diff --git a/core/modules/menu_link/menu_link.info.yml b/core/modules/menu_link/menu_link.info.yml
new file mode 100644
index 0000000..2c90e90
--- /dev/null
+++ b/core/modules/menu_link/menu_link.info.yml
@@ -0,0 +1,8 @@
+name: Menu link
+type: module
+description: 'Defines a menu link field type'
+package: Field types
+version: VERSION
+core: 8.x
+dependencies:
+  - field
diff --git a/core/modules/menu_link/src/Plugin/Field/FieldType/MenuLinkItem.php b/core/modules/menu_link/src/Plugin/Field/FieldType/MenuLinkItem.php
new file mode 100644
index 0000000..5cc31a2
--- /dev/null
+++ b/core/modules/menu_link/src/Plugin/Field/FieldType/MenuLinkItem.php
@@ -0,0 +1,229 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_link\Plugin\Field\FieldType\MenuLinkItem.
+ */
+
+namespace Drupal\menu_link\Plugin\Field\FieldType;
+
+use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\DataDefinitionInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\system\Entity\Menu;
+
+/**
+ * Defines a menu link field type which stores the link, parent and menu.
+ *
+ * @FieldType(
+ *   id = "menu_link",
+ *   label = @Translation("Menu link"),
+ *   description = @Translation("Stores a title, menu and parent to insert a link to the current entity."),
+ *   default_widget = "menu_link_default"
+ * )
+ */
+class MenuLinkItem extends FieldItemBase {
+
+  /**
+   * The menu plugin manager.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
+   */
+  protected $menuPluginManager;
+
+  /**
+   * The menu parent form selector.
+   *
+   * @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
+   */
+  protected $menuParentFormSelector;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) {
+    parent::__construct($definition, $name, $parent);
+
+    $this->menuPluginManager = \Drupal::service('plugin.manager.menu.link');
+    $this->menuParentFormSelector = \Drupal::service('menu.parent_form_selector');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultFieldSettings() {
+    $settings = parent::defaultFieldSettings();
+
+    $settings['available_menus'] = ['main'];
+    $settings['parent'] = ['main:'];
+    return $settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
+    $form = parent::fieldSettingsForm($form, $form_state);
+
+    $menu_options = $this->getMenuNames();
+
+    $form['available_menus'] = [
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Available menus'),
+      '#default_value' => $this->getSetting('available_menus'),
+      '#options' => $menu_options,
+      '#description' => $this->t('The menus available to place links in for this kind of entity.'),
+    ];
+    $form['parent'] = $this->menuParentFormSelector->getParentSelectOptions($this->getSetting('parent'));
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
+    $definitions = [];
+
+    $definitions['menu_name'] = DataDefinition::create('string')
+      ->setLabel(t('Menu'));
+    $definitions['parent'] = DataDefinition::create('string')
+      ->setLabel(t('Menu link parent'));
+    $definitions['weight'] = DataDefinition::create('integer')
+      ->setLabel(t('Menu link weight'));
+
+    return $definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function schema(FieldStorageDefinitionInterface $field_definition) {
+    $schema = [];
+
+    $schema['columns']['menu_name'] = [
+      'description' => 'The menu of the link',
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    ];
+    $schema['columns']['parent'] = [
+      'description' => 'The parent of the menu link',
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    ];
+
+    $schema['columns']['weight'] = [
+      'description' => 'The weight of the menu link',
+      'type' => 'int',
+    ];
+
+    return $schema;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function insert() {
+    parent::insert();
+
+    $this->doSave();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function update() {
+    parent::update();
+
+    $this->doSave();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    parent::delete();
+
+    $plugin_id = $this->getMenuPluginId();
+    if ($this->menuPluginManager->hasDefinition($plugin_id)) {
+      $this->menuPluginManager->removeDefinition($plugin_id);
+    }
+  }
+
+  /**
+   * Saves the plugin definition.
+   */
+  protected function doSave() {
+    $plugin_id = $this->getMenuPluginId();
+
+    // When the entity is saved via a plugin instance, we should not call
+    // the menu tree manager to update the definition a second time.
+    if (!$this->menuPluginManager->hasDefinition($plugin_id)) {
+      $this->menuPluginManager->addDefinition($plugin_id, $this->getMenuPluginDefinition());
+    }
+    else {
+     $this->menuPluginManager->updateDefinition($plugin_id, $this->getMenuPluginDefinition(), FALSE);
+    }
+  }
+
+  /**
+   * Generates the plugin ID for the associated menu link.
+   *
+   * @return string
+   */
+  public function getMenuPluginId() {
+    $field_name = $this->definition->getFieldDefinition()->getName();
+    $entity_type_id = $this->getEntity()->getEntityTypeId();
+    return 'menu_link_field:' . "{$entity_type_id}_{$field_name}_{$this->getEntity()->uuid()}";
+  }
+
+  /**
+   * Generates the plugin definition of the associated menu link.
+   *
+   * @return array
+   */
+  protected function getMenuPluginDefinition() {
+    $menu_definition = [];
+    $entity = $this->getEntity();
+    $menu_definition['id'] = $this->getPluginId();
+    $menu_definition['title'] = $entity->label();
+    $menu_definition['menu_name'] = $this->values['menu_name'];
+    $menu_definition['parent'] = $this->values['parent'];
+    $menu_definition['weight'] = isset($this->values['weight']) ? $this->values['weight'] : 0;
+    $menu_definition['class'] = '\Drupal\menu_link\Plugin\Menu\MenuLinkField';
+    $menu_definition['form_class'] = '\Drupal\menu_link\Plugin\Menu\Form\MenuLinkFieldForm';
+    $menu_definition['metadata']['entity_id'] = $entity->id();
+    $menu_definition['metadata']['entity_type_id'] = $entity->getEntityTypeId();
+    $menu_definition['metadata']['field_name'] = $this->definition->getFieldDefinition()->getName();
+    $menu_definition['metadata']['translateable'] = is_subclass_of($entity, '\Drupal\Core\TypedData\TranslatableInterface');
+
+    $url = $entity->urlInfo();
+    $menu_definition['route_name'] = $url->getRouteName();
+    $menu_definition['route_parameters'] = $url->getRouteParameters();
+
+    return $menu_definition;
+  }
+
+  /**
+   * Returns available menu names.
+   *
+   * @return string[]
+   *   Returns menu labels, keyed by menu ID.
+   */
+  protected function getMenuNames() {
+    if ($custom_menus = Menu::loadMultiple()) {
+      foreach ($custom_menus as $menu_name => $menu) {
+        $custom_menus[$menu_name] = $menu->label();
+      }
+      asort($custom_menus);
+    }
+
+    return $custom_menus;
+  }
+
+}
diff --git a/core/modules/menu_link/src/Plugin/Field/FieldWidget/MenuLinkWidget.php b/core/modules/menu_link/src/Plugin/Field/FieldWidget/MenuLinkWidget.php
new file mode 100644
index 0000000..1c0510a
--- /dev/null
+++ b/core/modules/menu_link/src/Plugin/Field/FieldWidget/MenuLinkWidget.php
@@ -0,0 +1,185 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_link\Plugin\Field\FieldWidget\MenuLinkWidget.
+ */
+
+namespace Drupal\menu_link\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Menu\MenuParentFormSelectorInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a widget for the menu_link field type.
+ *
+ * @FieldWidget(
+ *   id = "menu_link_default",
+ *   label = @Translation("Menu link"),
+ *   field_types = {
+ *     "menu_link"
+ *   }
+ * )
+ */
+class MenuLinkWidget extends WidgetBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The parent menu link selector.
+   *
+   * @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
+   */
+  protected $menuParentSelector;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, MenuParentFormSelectorInterface $menu_parent_selector, AccountInterface $account) {
+    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
+
+    $this->menuParentSelector = $menu_parent_selector;
+    $this->account = $account;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $plugin_id,
+      $plugin_definition,
+      $configuration['field_definition'],
+      $configuration['settings'],
+      $configuration['third_party_settings'],
+      $container->get('menu.parent_form_selector'),
+      $container->get('current_user')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+
+    $default_weight = isset($items[$delta]->weight) ? $items[$delta]->weight : 0;
+
+    $available_menus = array_filter($items->getSetting('available_menus'));
+    $available_menus = array_combine($available_menus, $available_menus);
+    $menu_names = array_keys($available_menus);
+    $menu = !empty($items[$delta]->menu) ? $items[$delta]->menu : reset($menu_names);
+    $parent = !empty($items[$delta]->parent) ? $items[$delta]->parent : '';
+    $default_menu_parent = "$menu:$parent";
+
+    if (!$this->account->hasPermission('administer menu')) {
+
+      $element['weight'] = [
+        '#type' => 'value',
+        '#value' => $default_weight,
+      ];
+      $element['menu_parent'] = [
+        '#type' => 'value',
+        '#value' => $default_menu_parent,
+      ];
+    }
+    else {
+
+      /** @var \Drupal\Core\Entity\EntityInterface $entity */
+      $entity = $items->getParent()->getValue();
+      $element['#pre_render'][] = [$this, 'preRenderMenuDetails'];
+      $element['enabled'] = [
+        '#type' => 'checkbox',
+        '#title' => $this->t('Provide a menu link'),
+        '#default_value' => (int) (bool) $items[$delta]->getPluginId(),
+      ];
+      $element['menu'] = [
+        '#type' => 'details',
+        '#title' => $this->t('Menu settings'),
+        '#open' => (bool) $items[$delta]->getPluginId(),
+        '#tree' => FALSE,
+        '#weight' => $entity->getEntityTypeId() == 'node' ? -2 : 0,
+        '#group' => $entity->getEntityTypeId() == 'node' ? 'advanced' : NULL,
+        '#attributes' => ['class' => ['menu-link-form']],
+        '#attached' => [
+          'library' => ['menu_ui/drupal.menu_ui'],
+        ],
+      ];
+
+      $plugin_id = $items[$delta]->getMenuPluginId();
+      $parent_element = $this->menuParentSelector->parentSelectElement($default_menu_parent, $plugin_id, $available_menus);
+
+      $element['menu_parent'] = $parent_element;
+      $element['menu_parent']['#title'] = $this->t('Parent item');
+      $element['menu_parent']['#attributes']['class'][] = 'menu-parent-select';
+
+      $element['weight'] = [
+        '#type' => 'number',
+        '#title' => $this->t('Weight'),
+        '#default_value' => $default_weight,
+        '#description' => $this->t('Menu links with lower weights are displayed before links with higher weights.'),
+      ];
+    }
+
+    return $element;
+  }
+
+  /**
+   * Pre-render callback: Builds a renderable array for menu links.
+   *
+   * @param array $element
+   *   A renderable array.
+   *
+   * @return array
+   *   A renderable array.
+   */
+  public function preRenderMenuDetails($element) {
+    $element['menu']['enabled'] = $element['enabled'];
+    $element['menu']['menu_parent'] = $element['menu_parent'];
+    $element['menu']['weight'] = $element['weight'];
+
+    // Hide the elements when enabled is disabled.
+    foreach (['menu_parent', 'weight'] as $form_element) {
+      $element['menu'][$form_element]['#states'] = [
+        'invisible' => [
+          'input[name="' . $element['menu']['enabled']['#name'] . '"' => ['checked' => FALSE],
+        ],
+      ];
+    }
+
+    unset($element['enabled'], $element['menu_parent'], $element['weight']);
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
+    parent::extractFormValues($items, $form, $form_state);
+
+    // Extract menu and parent menu link from single select element.
+    foreach ($items as $delta => $item) {
+      if (!empty($item->enabled) && !empty($item->menu_parent) && $item->menu_parent != ':') {
+        list($item->menu_name, $item->parent) = explode(':', $item->menu_parent, 2);
+      }
+      else {
+        $item->menu_name = '';
+        $item->parent = '';
+      }
+      unset($item->enabled);
+      unset($item->menu_parent);
+    }
+  }
+
+}
diff --git a/core/modules/menu_link/src/Plugin/Menu/Form/MenuLinkFieldForm.php b/core/modules/menu_link/src/Plugin/Menu/Form/MenuLinkFieldForm.php
new file mode 100644
index 0000000..3ab3126
--- /dev/null
+++ b/core/modules/menu_link/src/Plugin/Menu/Form/MenuLinkFieldForm.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_link\Plugin\Menu\Form\MenuLinkFieldForm.
+ */
+
+namespace Drupal\menu_link\Plugin\Menu\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Menu\Form\MenuLinkDefaultForm;
+
+/**
+ * Provides the menu link edit form for the field-based menu link.
+ */
+class MenuLinkFieldForm extends MenuLinkDefaultForm {
+
+  /**
+   * @var \Drupal\menu_link\Plugin\Menu\MenuLinkField
+   */
+  protected $menuLink;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    $entity = $this->menuLink->getEntity();
+
+    $form['info'] = [
+      '#type' => 'item',
+      '#title' => $this->t('This link is provided by the %type: <a href="@url">@label</a>. The path cannot be edited.', [
+        '%type' => $entity->getEntityType()->getLabel(),
+        '@url' => $entity->url(),
+        '@label' => $entity->label(),
+      ]),
+    ];
+
+    return $form;
+  }
+
+}
+
diff --git a/core/modules/menu_link/src/Plugin/Menu/MenuLinkField.php b/core/modules/menu_link/src/Plugin/Menu/MenuLinkField.php
new file mode 100644
index 0000000..05da9a6
--- /dev/null
+++ b/core/modules/menu_link/src/Plugin/Menu/MenuLinkField.php
@@ -0,0 +1,150 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_link\Plugin\Menu\MenuLinkField.
+ */
+
+namespace Drupal\menu_link\Plugin\Menu;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Menu\MenuLinkBase;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a menu link plugin for field-based menu links.
+ */
+class MenuLinkField extends MenuLinkBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * Entities IDs to load.
+   *
+   * It is an array of entity IDs keyed by entity IDs.
+   *
+   * @var array
+   */
+  protected static $entityIdsToLoad = array();
+
+  /**
+   * The entity connected to this plugin instance.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $entity;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
+   * Constructs a new MenuLinkField object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityManager = $entity_manager;
+    $this->languageManager = $language_manager;
+
+    $entity_type_id = $this->pluginDefinition['metadata']['entity_type_id'];
+    $entity_id = $this->pluginDefinition['metadata']['entity_id'];
+    // Builds a list of entity IDs to take advantage of the more efficient
+    // EntityStorageInterface::loadMultiple() in getEntity() at render time.
+    static::$entityIdsToLoad[$entity_type_id][$entity_id] = $entity_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager'),
+      $container->get('language_manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTitle() {
+    // We only need to get the title from the actual entity if it may be a
+    // translation based on the current language context. This can only happen
+    // if the site is configured to be multilingual.
+    if (!empty($this->pluginDefinition['metadata']['translateable']) && $this->languageManager->isMultilingual()) {
+      return $this->getEntity()->getTitle();
+    }
+    return $this->pluginDefinition['title'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->pluginDefinition['description'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function updateLink(array $new_definition_values, $persist) {
+    $field_name = $this->getMetaData()['field_name'];
+
+    $this->pluginDefinition = $new_definition_values + $this->getPluginDefinition();
+    if ($persist) {
+      $updated = [];
+      foreach ($new_definition_values as $key => $value) {
+        $field = $this->getEntity()->{$field_name};
+        if (isset($field->{$key})) {
+          $field->{$key} = $value;
+          $updated[] = $key;
+        }
+      }
+      if ($updated) {
+        $this->getEntity()->save();
+      }
+    }
+
+    return $this->pluginDefinition;
+  }
+
+  /**
+   * Loads the entity the field was attached to.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   Returns the entity, if exists.
+   */
+  public function getEntity() {
+    if (empty($this->entity)) {
+      $entity_type_id = $this->pluginDefinition['metadata']['entity_type_id'];
+      $entity_id = $this->pluginDefinition['metadata']['entity_id'];
+      $this->entity = $this->entityManager->getStorage($entity_type_id)->load($entity_id);
+    }
+    return $this->entity;
+  }
+
+}
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 7d4145a..79264a4 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -128,345 +128,6 @@ function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginIn
 }
 
 /**
- * Implements hook_ENTITY_TYPE_insert() for node entities.
- */
-function menu_ui_node_insert(EntityInterface $node) {
-  menu_ui_node_save($node);
-}
-
-/**
- * Implements hook_ENTITY_TYPE_update() for node entities.
- */
-function menu_ui_node_update(EntityInterface $node) {
-  menu_ui_node_save($node);
-}
-
-/**
- * Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes.
- */
-function menu_ui_node_save(EntityInterface $node) {
-  if (!empty($node->menu)) {
-    /** @var \Drupal\menu_link_content\MenuLinkContentInterface $entity */
-    $definition = $node->menu;
-    if (trim($definition['title'])) {
-      if (!empty($definition['entity_id'])) {
-        $entity = MenuLinkContent::load($definition['entity_id']);
-        $entity->enabled->value = 1;
-        $entity->title->value = trim($definition['title']);
-        $entity->description->value = trim($definition['description']);
-        $entity->menu_name->value = $definition['menu_name'];
-        $entity->parent->value = $definition['parent'];
-        $entity->weight->value = isset($definition['weight']) ? $definition['weight'] : 0;
-      }
-      else {
-        // Create a new menu_link_content entity.
-        $entity = entity_create('menu_link_content', array(
-          'title' => trim($definition['title']),
-          'description' => trim($definition['description']),
-          'route_name' => 'entity.node.canonical',
-          'route_parameters' => array('node' => $node->id()),
-          'menu_name' => $definition['menu_name'],
-          'parent' => $definition['parent'],
-          'weight' => isset($definition['weight']) ? $definition['weight'] : 0,
-          'enabled' => 1,
-          'langcode' => $node->getUntranslated()->language()->getId(),
-        ));
-      }
-      if (!$entity->save()) {
-        drupal_set_message(t('There was an error saving the menu link.'), 'error');
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_ENTITY_TYPE_predelete() for node entities.
- */
-function menu_ui_node_predelete(EntityInterface $node) {
-  // Delete all MenuLinkContent links that point to this node.
-  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
-  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
-  $result = $menu_link_manager->loadLinksByRoute('entity.node.canonical', array('node' => $node->id()));
-
-  if (!empty($result)) {
-    foreach ($result as $id => $instance) {
-      if ($instance->isDeletable() && strpos($id, 'menu_link_content:') === 0) {
-        $instance->deleteLink();
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_node_prepare_form().
- */
-function menu_ui_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state) {
-  if (!$form_state->get('menu_link_definition')) {
-    // Prepare the node for the edit form so that $node->menu always exists.
-    /** @var \Drupal\node\NodeTypeInterface $node_type */
-    $node_type = $node->type->entity;
-    $menu_name = strtok($node_type->getThirdPartySetting('menu_ui', 'parent', 'main:'), ':');
-    $definition = FALSE;
-    if ($node->id()) {
-      $id = FALSE;
-      // Give priority to the default menu
-      $type_menus = $node_type->getThirdPartySetting('menu_ui', 'available_menus', array('main'));
-      if (in_array($menu_name, $type_menus)) {
-        $query = \Drupal::entityQuery('menu_link_content')
-          ->condition('route_name', 'entity.node.canonical')
-          ->condition('route_parameters', serialize(array('node' => $node->id())))
-          ->condition('menu_name', $menu_name)
-          ->sort('id', 'ASC')
-          ->range(0, 1);
-        $result = $query->execute();
-
-        $id = (!empty($result)) ? reset($result) : FALSE;
-      }
-      // Check all allowed menus if a link does not exist in the default menu.
-      if (!$id && !empty($type_menus)) {
-        $query = \Drupal::entityQuery('menu_link_content')
-          ->condition('route_name', 'entity.node.canonical')
-          ->condition('route_parameters', serialize(array('node' => $node->id())))
-          ->condition('menu_name', array_values($type_menus), 'IN')
-          ->sort('id', 'ASC')
-          ->range(0, 1);
-        $result = $query->execute();
-
-        $id = (!empty($result)) ? reset($result) : FALSE;
-      }
-      if ($id) {
-        $menu_link = MenuLinkContent::load($id);
-        $definition = array(
-          'entity_id' => $menu_link->id(),
-          'id' => $menu_link->getPluginId(),
-          'title' => $menu_link->getTitle(),
-          'description' => $menu_link->getDescription(),
-          'menu_name' => $menu_link->getMenuName(),
-          'parent' => $menu_link->getParentId(),
-          'weight' => $menu_link->getWeight(),
-        );
-      }
-    }
-
-    if (!$definition) {
-      $definition = array(
-        'entity_id' => 0,
-        'id' => '',
-        'title' => '',
-        'description' => '',
-        'menu_name' => $menu_name,
-        'parent' => '',
-        'weight' => 0,
-      );
-    }
-    // Set default values.
-    $form_state->set('menu_link_definition', $definition);
-  }
-}
-
-/**
- * Implements hook_form_BASE_FORM_ID_alter() for node_form.
- *
- * Adds menu item fields to the node form.
- *
- * @see menu_ui_node_submit()
- */
-function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) {
-  // Generate a list of possible parents (not including this link or descendants).
-  // @todo This must be handled in a #process handler.
-  $node = $form_state->getFormObject()->getEntity();
-  $definition = $form_state->get('menu_link_definition');
-  /** @var \Drupal\node\NodeTypeInterface $node_type */
-  $node_type = $node->type->entity;
-  /** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
-  $menu_parent_selector = \Drupal::service('menu.parent_form_selector');
-  $menu_names = menu_ui_get_menus();
-  $type_menus = $node_type->getThirdPartySetting('menu_ui', 'available_menus', array('main'));
-  $available_menus = array();
-  foreach ($type_menus as $menu) {
-    $available_menus[$menu] = $menu_names[$menu];
-  }
-  if ($definition['id']) {
-    $default = $definition['menu_name'] . ':' . $definition['parent'];
-  }
-  else {
-    $default = $node_type->getThirdPartySetting('menu_ui', 'parent', 'main:');
-  }
-  $parent_element = $menu_parent_selector->parentSelectElement($default,  $definition['id'], $available_menus);
-  // If no possible parent menu items were found, there is nothing to display.
-  if (empty($parent_element)) {
-    return;
-  }
-
-  $form['menu'] = array(
-    '#type' => 'details',
-    '#title' => t('Menu settings'),
-    '#access' => \Drupal::currentUser()->hasPermission('administer menu'),
-    '#open' => (bool) $definition['id'],
-    '#group' => 'advanced',
-    '#attached' => array(
-      'library' => array('menu_ui/drupal.menu_ui'),
-    ),
-    '#tree' => TRUE,
-    '#weight' => -2,
-    '#attributes' => array('class' => array('menu-link-form')),
-  );
-  $form['menu']['enabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Provide a menu link'),
-    '#default_value' => (int) (bool) $definition['id'],
-  );
-  $form['menu']['link'] = array(
-    '#type' => 'container',
-    '#parents' => array('menu'),
-    '#states' => array(
-      'invisible' => array(
-        'input[name="menu[enabled]"]' => array('checked' => FALSE),
-      ),
-    ),
-  );
-
-  // Populate the element with the link data.
-  foreach (array('id', 'entity_id') as $key) {
-    $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $definition[$key]);
-  }
-
-  $form['menu']['link']['title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Menu link title'),
-    '#default_value' => $definition['title'],
-  );
-
-  $form['menu']['link']['description'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Description'),
-    '#default_value' => $definition['description'],
-    '#rows' => 1,
-    '#description' => t('Shown when hovering over the menu link.'),
-  );
-
-  $form['menu']['link']['menu_parent'] = $parent_element;
-  $form['menu']['link']['menu_parent']['#title'] = t('Parent item');
-  $form['menu']['link']['menu_parent']['#attributes']['class'][] = 'menu-parent-select';
-
-  $form['menu']['link']['weight'] = array(
-    '#type' => 'number',
-    '#title' => t('Weight'),
-    '#default_value' => $definition['weight'],
-    '#description' => t('Menu links with lower weights are displayed before links with higher weights.'),
-  );
-}
-
-/**
- * Implements hook_node_submit().
- *
- * @see menu_ui_form_node_form_alter()
- */
-function menu_ui_node_submit(EntityInterface $node, $form, FormStateInterface $form_state) {
-  if (!$form_state->isValueEmpty('menu')) {
-    $definition = $form_state->getValue('menu');
-    if (empty($definition['enabled'])) {
-      if ($definition['entity_id']) {
-        $entity = MenuLinkContent::load($definition['entity_id']);
-        $entity->delete();
-      }
-    }
-    elseif (trim($definition['title']))  {
-      // Decompose the selected menu parent option into 'menu_name' and 'parent',
-      // if the form used the default parent selection widget.
-      if (!empty($definition['menu_parent'])) {
-        list($menu_name, $parent) = explode(':', $definition['menu_parent'], 2);
-        $definition['menu_name'] = $menu_name;
-        $definition['parent'] = $parent;
-      }
-      // @todo Figure out how to save this data without adding non-Field API
-      //   properties to the node entity. https://www.drupal.org/node/2310173
-      //   We have to tack this onto the node so we can save it later when we
-      //   have a node ID for any new node.
-      $node->menu = $definition;
-    }
-  }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Adds menu options to the node type form.
- *
- * @see NodeTypeForm::form().
- * @see menu_ui_form_node_type_form_submit().
- */
-function menu_ui_form_node_type_form_alter(&$form, FormStateInterface $form_state) {
-  /** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
-  $menu_parent_selector = \Drupal::service('menu.parent_form_selector');
-  $menu_options = menu_ui_get_menus();
-  /** @var \Drupal\node\NodeTypeInterface $type */
-  $type = $form_state->getFormObject()->getEntity();
-  $form['menu'] = array(
-    '#type' => 'details',
-    '#title' => t('Menu settings'),
-    '#attached' => array(
-      'library' => array('menu_ui/drupal.menu_ui.admin'),
-    ),
-    '#group' => 'additional_settings',
-  );
-  $form['menu']['menu_options'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Available menus'),
-    '#default_value' => $type->getThirdPartySetting('menu_ui', 'available_menus', array('main')),
-    '#options' => $menu_options,
-    '#description' => t('The menus available to place links in for this content type.'),
-  );
-  // @todo See if we can avoid pre-loading all options by changing the form or
-  //   using a #process callback. https://www.drupal.org/node/2310319
-  //   To avoid an 'illegal option' error after saving the form we have to load
-  //   all available menu parents. Otherwise, it is not possible to dynamically
-  //   add options to the list using ajax.
-  $options = $menu_parent_selector->getParentSelectOptions('');
-  $form['menu']['menu_parent'] = array(
-    '#type' => 'select',
-    '#title' => t('Default parent item'),
-    '#default_value' => $type->getThirdPartySetting('menu_ui', 'parent', 'main:'),
-    '#options' => $options,
-    '#description' => t('Choose the menu item to be the default parent for a new link in the content authoring form.'),
-    '#attributes' => array('class' => array('menu-title-select')),
-  );
-
-  $form['actions']['submit']['#validate'][] = 'menu_ui_form_node_type_form_validate';
-  $form['#entity_builders'][] = 'menu_ui_form_node_type_form_builder';
-}
-
-/**
- * Submit handler for forms with menu options.
- *
- * @see menu_ui_form_node_type_form_alter().
- */
-function menu_ui_form_node_type_form_validate(&$form, FormStateInterface $form_state) {
-  $available_menus = array_filter($form_state->getValue('menu_options'));
-  // If there is at least one menu allowed, the selected item should be in
-  // one of them.
-  if (count($available_menus)) {
-    $menu_item_id_parts = explode(':', $form_state->getValue('menu_parent'));
-    if (!in_array($menu_item_id_parts[0], $available_menus)) {
-      $form_state->setErrorByName('menu_parent', t('The selected menu item is not under one of the selected menus.'));
-    }
-  }
-  else {
-    $form_state->setValue('menu_parent', '');
-  }
-}
-
-/**
- * Entity builder for the node type form with menu options.
- *
- * @see menu_ui_form_node_type_form_alter().
- */
-function menu_ui_form_node_type_form_builder($entity_type, NodeTypeInterface $type, &$form, FormStateInterface $form_state) {
-  $type->setThirdPartySetting('menu_ui', 'available_menus', array_values(array_filter($form_state->getValue('menu_options'))));
-  $type->setThirdPartySetting('menu_ui', 'parent', $form_state->getValue('menu_parent'));
-}
-
-/**
  * Return an associative array of the custom menus names.
  *
  * @param $all
diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php
index 2415032..75ab6a2 100644
--- a/core/modules/menu_ui/src/MenuForm.php
+++ b/core/modules/menu_ui/src/MenuForm.php
@@ -224,6 +224,8 @@ protected function buildOverviewForm(array &$form, FormStateInterface $form_stat
     // We indicate that a menu administrator is running the menu access check.
     $this->getRequest()->attributes->set('_menu_admin', TRUE);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     );
diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/src/Tests/MenuNodeTest.php
index 99798d6..ed8ff07 100644
--- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuNodeTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\menu_ui\Tests;
 
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\simpletest\WebTestBase;
 use Drupal\menu_link_content\Entity\MenuLinkContent;
 
@@ -22,7 +24,22 @@ class MenuNodeTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('menu_ui', 'test_page_test', 'node', 'block');
+  public static $modules = array('menu_ui', 'test_page_test', 'node', 'block', 'menu_link');
+
+  /**
+   * @var \Drupal\field\Entity\FieldConfig
+   */
+  protected $fieldConfig;
+
+  /**
+   * @var \Drupal\field\Entity\FieldStorageConfig
+   */
+  protected $fieldStorageConfig;
+
+  /**
+   * @var \Drupal\field\Entity\FieldStorageConfig
+   */
+  protected $fieldConfigArticle;
 
   protected function setUp() {
     parent::setUp();
@@ -30,6 +47,25 @@ protected function setUp() {
     $this->drupalPlaceBlock('system_menu_block:main');
 
     $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+
+    $this->fieldStorageConfig = FieldStorageConfig::create(['field_name' => 'menu', 'entity_type' => 'node', 'type' => 'menu_link']);
+    $this->fieldStorageConfig->save();
+    $this->fieldConfig = FieldConfig::create(['entity_type' => 'node', 'bundle' => 'page', 'field_name' => 'menu']);
+    $this->fieldConfig->save();
+    entity_get_form_display('node', 'page', 'default')
+      ->setComponent('menu', [
+        'type' => 'menu_link_default',
+      ])
+      ->save();
+
+    $this->fieldConfigArticle = FieldConfig::create(['entity_type' => 'node', 'bundle' => 'article', 'field_name' => 'menu']);
+    $this->fieldConfigArticle->save();
+    entity_get_form_display('node', 'article', 'default')
+      ->setComponent('menu', [
+        'type' => 'menu_link_default',
+      ])
+      ->save();
 
     $this->admin_user = $this->drupalCreateUser(array(
       'access administration pages',
@@ -47,15 +83,12 @@ protected function setUp() {
    */
   function testMenuNodeFormWidget() {
     // Disable the default main menu, so that no menus are enabled.
-    $edit = array(
-      'menu_options[main]' => FALSE,
-    );
-    $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->fieldConfig->settings['available_menus']['menu'] = FALSE;
+    $this->fieldConfig->save();
 
     // Verify that no menu settings are displayed and nodes can be created.
     $this->drupalGet('node/add/page');
     $this->assertText(t('Create Basic page'));
-    $this->assertNoText(t('Menu settings'));
     $node_title = $this->randomMachineName();
     $edit = array(
       'title[0][value]' => $node_title,
@@ -67,22 +100,15 @@ function testMenuNodeFormWidget() {
 
     // Test that we cannot set a menu item from a menu that is not set as
     // available.
-    $edit = array(
-      'menu_options[tools]' => 1,
-      'menu_parent' => 'main:',
-    );
-    $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
-    $this->assertText(t('The selected menu item is not under one of the selected menus.'));
-    $this->assertNoRaw(t('The content type %name has been updated.', array('%name' => 'Basic page')));
+    $this->fieldConfig->settings['available_menus']['tools'] = 'tools';
+    $this->fieldConfig->settings['parent'] = 'main:';
+    $this->fieldConfig->save();
 
     // Enable Tools menu as available menu.
-    $edit = array(
-      'menu_options[main]' => 1,
-      'menu_options[tools]' => 1,
-      'menu_parent' => 'main:',
-    );
-    $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
-    $this->assertRaw(t('The content type %name has been updated.', array('%name' => 'Basic page')));
+    $this->fieldConfig->settings['available_menus']['tools'] = 'tools';
+    $this->fieldConfig->settings['available_menus']['main'] = 'main';
+    $this->fieldConfig->settings['parent'] = 'main:';
+    $this->fieldConfig->save();
 
     // Create a node.
     $node_title = $this->randomMachineName();
@@ -98,7 +124,7 @@ function testMenuNodeFormWidget() {
 
     // Edit the node, enable the menu link setting, but skip the link title.
     $edit = array(
-      'menu[enabled]' => 1,
+      'menu[0][enabled]' => 1,
     );
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
     // Assert that there is no link for the node.
@@ -107,9 +133,8 @@ function testMenuNodeFormWidget() {
 
     // Edit the node and create a menu link.
     $edit = array(
-      'menu[enabled]' => 1,
-      'menu[title]' => $node_title,
-      'menu[weight]' => 17,
+      'menu[0][enabled]' => 1,
+      'menu[0][weight]' => 17,
     );
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
     // Assert that the link exists.
@@ -117,11 +142,11 @@ function testMenuNodeFormWidget() {
     $this->assertLink($node_title);
 
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertFieldById('edit-menu-weight', 17, 'Menu weight correct in edit form');
+    $this->assertFieldById('edit-menu-0-weight', 17, 'Menu weight correct in edit form');
 
     // Edit the node and remove the menu link.
     $edit = array(
-      'menu[enabled]' => FALSE,
+      'menu[0][enabled]' => FALSE,
     );
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
     // Assert that there is no link for the node.
@@ -129,13 +154,8 @@ function testMenuNodeFormWidget() {
     $this->assertNoLink($node_title);
 
     // Add a menu link to the Administration menu.
-    $item = entity_create('menu_link_content', array(
-      'route_name' => 'entity.node.canonical',
-      'route_parameters' => array('node' => $node->id()),
-      'title' => $this->randomMachineName(16),
-      'menu_name' => 'admin',
-    ));
-    $item->save();
+    $node->menu->menu_name = 'admin';
+    $node->save();
 
     // Assert that disabled Administration menu is not shown on the
     // node/$nid/edit page.
@@ -143,29 +163,26 @@ function testMenuNodeFormWidget() {
     $this->assertText('Provide a menu link', 'Link in not allowed menu not shown in node edit form');
     // Assert that the link is still in the Administration menu after save.
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
-    $link = MenuLinkContent::load($item->id());
+    $link = \Drupal::service('plugin.manager.menu.link')->getDefinition($node->menu->first()->getMenuPluginId());
     $this->assertTrue($link, 'Link in not allowed menu still exists after saving node');
 
     // Move the menu link back to the Tools menu.
-    $item->menu_name->value = 'tools';
-    $item->save();
+    $node->menu->menu_name = 'tools';
+    $node->save();
+
     // Create a second node.
     $child_node = $this->drupalCreateNode(array('type' => 'article'));
     // Assign a menu link to the second node, being a child of the first one.
-    $child_item = entity_create('menu_link_content', array(
-      'route_name' => 'entity.node.canonical',
-      'route_parameters' => array('node' => $child_node->id()),
-      'title' => $this->randomMachineName(16),
-      'parent' => $item->getPluginId(),
-      'menu_name' => $item->getMenuName(),
-    ));
-    $child_item->save();
+    $child_node->menu->parent = $node->menu->first()->getMenuPluginId();
+    $child_node->menu->menu_name = $node->menu->menu_name;
+    $child_node->save();
+
     // Edit the first node.
     $this->drupalGet('node/'. $node->id() .'/edit');
     // Assert that it is not possible to set the parent of the first node to itself or the second node.
-    $this->assertNoOption('edit-menu-menu-parent', 'tools:'. $item->getPluginId());
-    $this->assertNoOption('edit-menu-menu-parent', 'tools:'. $child_item->getPluginId());
+    $this->assertNoOption('edit-menu-0-menu-parent', 'tools:'. $node->menu->first()->getMenuPluginId());
+    $this->assertNoOption('edit-menu-0-menu-parent', 'tools:'. $child_node->menu->first()->getMenuPluginId());
     // Assert that unallowed Administration menu is not available in options.
-    $this->assertNoOption('edit-menu-menu-parent', 'admin:');
+    $this->assertNoOption('edit-menu-0-menu-parent', 'admin:');
   }
 }
diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php
index 22bade6..073e872 100644
--- a/core/modules/system/src/Controller/SystemController.php
+++ b/core/modules/system/src/Controller/SystemController.php
@@ -124,6 +124,8 @@ public function overview($link_id) {
     $parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
     $tree = $this->menuLinkTree->load(NULL, $parameters);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     );
diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
index 16af329..17d3c29 100644
--- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
@@ -146,6 +146,8 @@ public function build() {
 
     $tree = $this->menuTree->load($menu_name, $parameters);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     );
diff --git a/core/modules/system/src/SystemManager.php b/core/modules/system/src/SystemManager.php
index 145705f..4a0022f 100644
--- a/core/modules/system/src/SystemManager.php
+++ b/core/modules/system/src/SystemManager.php
@@ -205,6 +205,8 @@ public function getAdminBlock(MenuLinkInterface $instance) {
     $parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
     $tree = $this->menuTree->load(NULL, $parameters);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     );
diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
index 22a2f7d..b4ad9a8 100644
--- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
+++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
@@ -9,7 +9,8 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
-use Drupal\node\Entity\NodeType;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
 
 /**
  * Tests breadcrumbs functionality.
@@ -32,7 +33,7 @@ class BreadcrumbTest extends MenuTestBase {
    *
    * @var array
    */
-  public static $modules = array('menu_test', 'block');
+  public static $modules = array('menu_test', 'block', 'menu_link');
 
   /**
    * Test paths in the Standard profile.
@@ -166,11 +167,19 @@ function testBreadCrumbs() {
     // @todo Also test all themes? Manually testing led to the suspicion that
     //   breadcrumbs may differ, possibly due to theme overrides.
     $menus = array('main', 'tools');
-    // Alter node type menu settings.
-    $node_type = NodeType::load($type);
-    $node_type->setThirdPartySetting('menu_ui', 'available_menus', $menus);
-    $node_type->setThirdPartySetting('menu_ui', 'parent', 'tools:');
-    $node_type->save();
+    // Add a menu field to the node type.
+    $field_storage_config = FieldStorageConfig::create(['field_name' => 'menu', 'entity_type' => 'node', 'type' => 'menu_link']);
+    $field_storage_config->save();
+    $field_config = FieldConfig::create(['entity_type' => 'node', 'bundle' => $type, 'field_name' => 'menu']);
+    $field_config->settings['available_menus'] = array_combine($menus, $menus);
+    $field_config->settings['parent'] = 'tools:';
+    $field_config->save();
+
+    entity_get_form_display('node', $type, 'default')
+      ->setComponent('menu', [
+        'type' => 'menu_link_default',
+      ])
+      ->save();
 
     foreach ($menus as $menu) {
       // Create a parent node in the current menu.
@@ -178,14 +187,11 @@ function testBreadCrumbs() {
       $node2 = $this->drupalCreateNode(array(
         'type' => $type,
         'title' => $title,
-        'menu' => array(
-          'enabled' => 1,
-          'title' => 'Parent ' . $title,
-          'description' => '',
-          'menu_name' => $menu,
-          'parent' => '',
-        ),
       ));
+      $node2->menu->title = 'Parent ' . $title;
+      $node2->menu->description = '';
+      $node2->menu->menu_name = $menu;
+      $node2->menu->parent = '';
 
       if ($menu == 'tools') {
         $parent = $node2;
@@ -204,7 +210,7 @@ function testBreadCrumbs() {
     $link = reset($menu_links);
 
     $edit = array(
-      'menu[menu_parent]' => $link->getMenuName() . ':' . $link->getPluginId(),
+      'menu[0][menu_parent]' => $link->getMenuName() . ':' . $link->getPluginId(),
     );
     $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published'));
     $expected = array(
@@ -212,10 +218,10 @@ function testBreadCrumbs() {
     );
     $trail = $home + $expected;
     $tree = $expected + array(
-      'node/' . $parent->id() => $parent->menu['title'],
+      'node/' . $parent->id() => $parent->menu->title,
     );
     $trail += array(
-      'node/' . $parent->id() => $parent->menu['title'],
+      'node/' . $parent->id() => $parent->menu->title,
     );
 
     // Add a taxonomy term/tag to last node, and add a link for that term to the
diff --git a/core/modules/system/src/Tests/System/AdminTest.php b/core/modules/system/src/Tests/System/AdminTest.php
index fee3cd9..8dc9aa0 100644
--- a/core/modules/system/src/Tests/System/AdminTest.php
+++ b/core/modules/system/src/Tests/System/AdminTest.php
@@ -131,6 +131,8 @@ protected function getTopLevelMenuLinks() {
     $parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
     $tree = $menu_tree->load(NULL, $parameters);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:flatten'),
     );
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 7b75cc9..67fe902 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1134,6 +1134,8 @@ function system_get_module_admin_tasks($module, array $info) {
     $parameters->setRoot('system.admin')->excludeRoot()->onlyEnabledLinks();
     $tree = $menu_tree->load('system.admin', $parameters);
     $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+      array('callable' => 'menu.default_tree_manipulators:loadEntities'),
       array('callable' => 'menu.default_tree_manipulators:checkAccess'),
       array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
       array('callable' => 'menu.default_tree_manipulators:flatten'),
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 7b75e89..9087753 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -210,6 +210,8 @@ function toolbar_prerender_toolbar_administration_tray(array $element) {
   $parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
   $tree = $menu_tree->load(NULL, $parameters);
   $manipulators = array(
+    array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+    array('callable' => 'menu.default_tree_manipulators:loadEntities'),
     array('callable' => 'menu.default_tree_manipulators:checkAccess'),
     array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     array('callable' => 'toolbar_menu_navigation_links'),
@@ -266,6 +268,8 @@ function toolbar_get_rendered_subtrees() {
   $parameters->setRoot('system.admin')->excludeRoot()->setMaxDepth(3)->onlyEnabledLinks();
   $tree = $menu_tree->load(NULL, $parameters);
   $manipulators = array(
+    array('callable' => 'menu.default_tree_manipulators:checkNodeAccess'),
+    array('callable' => 'menu.default_tree_manipulators:loadEntities'),
     array('callable' => 'menu.default_tree_manipulators:checkAccess'),
     array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
     array('callable' => 'toolbar_menu_navigation_links'),
