diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php b/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php
deleted file mode 100644
index 6fad35c..0000000
--- a/core/modules/shortcut/lib/Drupal/shortcut/Access/LinkDeleteAccessCheck.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains Drupal\shortcut\Access\LinkDeleteAccessCheck.
- */
-
-namespace Drupal\shortcut\Access;
-
-use Drupal\Core\Access\StaticAccessCheckInterface;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Provides an access check for shortcut link delete routes.
- */
-class LinkDeleteAccessCheck implements StaticAccessCheckInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function appliesTo() {
-    return array('_access_shortcut_link_delete');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(Route $route, Request $request) {
-    $menu_link = $request->attributes->get('menu_link');
-    $set_name = str_replace('shortcut-', '', $menu_link['menu_name']);
-    if ($shortcut_set = shortcut_set_load($set_name)) {
-      return shortcut_set_edit_access($shortcut_set);
-    }
-  }
-
-}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Access/ShortcutLinkUpdateAccessCheck.php b/core/modules/shortcut/lib/Drupal/shortcut/Access/ShortcutLinkUpdateAccessCheck.php
new file mode 100644
index 0000000..2aa0485
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Access/ShortcutLinkUpdateAccessCheck.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\shortcut\Access\ShortcutLinkUpdateAccessCheck.
+ */
+
+namespace Drupal\shortcut\Access;
+
+use Drupal\Core\Access\StaticAccessCheckInterface;
+use Drupal\Core\Entity\EntityManager;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides an access check for shortcut link delete routes.
+ */
+class ShortcutLinkUpdateAccessCheck implements StaticAccessCheckInterface {
+
+  /**
+   * The shortcut set storage.
+   *
+   * @var \Drupal\shortcut\ShortcutSetStorageControllerInterface
+   */
+  protected $shortcutSetStorage;
+
+  /**
+   * Constructs a new ShortcutLinkUpdateAccessCheck.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->shortcutSetStorage = $entity_manager->getStorageController('shortcut_set');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function appliesTo() {
+    return array('_access_shortcut_link_update');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(Route $route, Request $request) {
+    $menu_link = $request->attributes->get('menu_link');
+    $set_name = str_replace('shortcut-', '', $menu_link['menu_name']);
+    if ($shortcut_set = $this->shortcutSetStorage->load($set_name)) {
+      return $shortcut_set->access('update');
+    }
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Controller/ShortcutSetController.php b/core/modules/shortcut/lib/Drupal/shortcut/Controller/ShortcutSetController.php
index a67b53b..7ae7795 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Controller/ShortcutSetController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Controller/ShortcutSetController.php
@@ -8,8 +8,6 @@
 namespace Drupal\shortcut\Controller;
 
 use Drupal\Core\Controller\ControllerInterface;
-use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Routing\PathBasedGeneratorInterface;
 use Drupal\shortcut\ShortcutSetInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -23,20 +21,6 @@
 class ShortcutSetController implements ControllerInterface {
 
   /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * Stores the entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManager
-   */
-  protected $entityManager;
-
-  /**
    * The URL generator.
    *
    * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
@@ -46,16 +30,10 @@ class ShortcutSetController implements ControllerInterface {
   /**
    * Constructs a new \Drupal\shortcut\Controller\ShortCutController object.
    *
-   * @param \Drupal\Core\Entity\EntityManager $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
    * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
    *   The URL generator.
    */
-   public function __construct(EntityManager $entity_manager, ModuleHandlerInterface $module_handler, PathBasedGeneratorInterface $url_generator) {
-     $this->entityManager = $entity_manager;
-     $this->moduleHandler = $module_handler;
+   public function __construct(PathBasedGeneratorInterface $url_generator) {
      $this->urlGenerator = $url_generator;
    }
 
@@ -64,8 +42,6 @@ public function __construct(EntityManager $entity_manager, ModuleHandlerInterfac
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('plugin.manager.entity'),
-      $container->get('module_handler'),
       $container->get('url_generator')
     );
   }
@@ -93,8 +69,7 @@ public function addShortcutLinkInline(ShortcutSetInterface $shortcut_set, Reques
         'link_title' => $title,
         'link_path' => $link,
       );
-      $this->moduleHandler->loadInclude('shortcut', 'admin.inc');
-      shortcut_admin_add_link($link, $shortcut_set);
+      $shortcut_set->addLink($link);
       if ($shortcut_set->save() == SAVED_UPDATED) {
         drupal_set_message(t('Added a shortcut for %title.', array('%title' => $link['link_title'])));
       }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkAddForm.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkAddForm.php
new file mode 100644
index 0000000..8035bc2
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkAddForm.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\shortcut\Form\ShortcutLinkAddForm.
+ */
+
+namespace Drupal\shortcut\Form;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\menu_link\MenuLinkStorageControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Builds the shortcut link add form.
+ */
+class ShortcutLinkAddForm extends ShortcutLinkFormBase {
+
+  /**
+   * The menu link storage.
+   *
+   * @var \Drupal\menu_link\MenuLinkStorageControllerInterface
+   */
+  protected $menuLinkStorage;
+
+  /**
+   * The shortcut set the link is being added to.
+   *
+   * @var \Drupal\shortcut\ShortcutSetInterface
+   */
+  protected $entity;
+
+  /**
+   * Constructs a new ShortcutLinkAddForm.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\menu_link\MenuLinkStorageControllerInterface $menu_link_storage
+   *   The menu link storage.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, MenuLinkStorageControllerInterface $menu_link_storage) {
+    parent::__construct($module_handler);
+    $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('plugin.manager.entity')->getStorageController('menu_link')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, array &$form_state) {
+    // Add the shortcut link to the set.
+    $shortcut_link = $form_state['values']['shortcut_link'];
+    $shortcut_link['menu_name'] = $this->entity->id();
+    $this->entity
+      ->addLink($shortcut_link)
+      ->save();
+    $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $this->entity->id();
+    drupal_set_message(t('Added a shortcut for %title.', array('%title' => $shortcut_link['link_title'])));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    unset($actions['delete']);
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getShortcutLink() {
+    drupal_set_title(t('Add new shortcut'));
+    return $this->menuLinkStorage->create(array(
+      'link_title' => '',
+      'link_path' => '',
+    ));
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkEditForm.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkEditForm.php
new file mode 100644
index 0000000..b6f2861
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkEditForm.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\shortcut\Form\ShortcutLinkEditForm.
+ */
+
+namespace Drupal\shortcut\Form;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Path\AliasManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Builds the shortcut link edit form.
+ */
+class ShortcutLinkEditForm extends ShortcutLinkFormBase {
+
+  /**
+   * The path alias manager.
+   *
+   * @var \Drupal\Core\Path\AliasManagerInterface
+   */
+  protected $aliasManager;
+
+  /**
+   * Constructs a new ShortcutLinkEditForm.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
+   *   The path alias manager.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, AliasManagerInterface $alias_manager) {
+    parent::__construct($module_handler);
+
+    $this->aliasManager = $alias_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $container->get('module_handler'),
+      $container->get('path.alias_manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getShortcutLink() {
+    $shortcut_link = clone $this->entity;
+    drupal_set_title(t('Editing @shortcut', array('@shortcut' => $shortcut_link['link_title'])));
+    $shortcut_link['link_path'] = ($shortcut_link['link_path'] == '<front>') ? '' : $this->aliasManager->getPathAlias($shortcut_link['link_path']);
+    return $shortcut_link;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, array &$form_state) {
+    $shortcut_link = $form_state['values']['shortcut_link'];
+
+    // Normalize the path in case it is an alias.
+    $shortcut_path = $this->aliasManager->getSystemPath($shortcut_link['link_path']);
+    if (empty($shortcut_path)) {
+      $shortcut_path = '<front>';
+    }
+    $shortcut_link['link_path'] = $shortcut_path;
+
+    foreach ($shortcut_link as $key => $value) {
+      $this->entity[$key] = $value;
+    }
+
+    $this->entity->save();
+    $set_name = str_replace('shortcut-', '' , $this->entity['menu_name']);
+    $form_state['redirect'] = "admin/config/user-interface/shortcut/manage/$set_name";
+    drupal_set_message(t('The shortcut %link has been updated.', array('%link' => $this->entity['link_title'])));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete(array $form, array &$form_state) {
+    $form_state['redirect'] = 'admin/config/user-interface/shortcut/link/' . $this->entity->id() . '/delete';
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkFormBase.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkFormBase.php
new file mode 100644
index 0000000..ca46aaa
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/ShortcutLinkFormBase.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\shortcut\Form\ShortcutLinkFormBase.
+ */
+
+namespace Drupal\shortcut\Form;
+
+use Drupal\Core\Entity\EntityControllerInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Provides a base form for shortcut links.
+ */
+abstract class ShortcutLinkFormBase extends EntityFormController implements EntityControllerInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, array &$form_state) {
+    $shortcut_link = $this->getShortcutLink();
+
+    $form['shortcut_link']['#tree'] = TRUE;
+    $form['shortcut_link']['link_title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#size' => 40,
+      '#maxlength' => 255,
+      '#default_value' => $shortcut_link['link_title'],
+      '#required' => TRUE,
+    );
+
+    $form['shortcut_link']['link_path'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Path'),
+      '#size' => 40,
+      '#maxlength' => 255,
+      '#field_prefix' => url(NULL, array('absolute' => TRUE)),
+      '#default_value' => $shortcut_link['link_path'],
+    );
+
+    return parent::form($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate(array $form, array &$form_state) {
+    if (!shortcut_valid_link($form_state['values']['shortcut_link']['link_path'])) {
+      form_set_error('shortcut_link][link_path', t('The link must correspond to a valid path on the site.'));
+    }
+  }
+
+  /**
+   * Gets the shortcut link for this form.
+   *
+   * @return \Drupal\menu_link\MenuLinkInterface
+   *   The shortcut link object.
+   */
+  abstract protected function getShortcutLink();
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/ShortcutSet.php b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/ShortcutSet.php
index d55c61b..07640f5 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/ShortcutSet.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/ShortcutSet.php
@@ -28,6 +28,7 @@
  *       "default" = "Drupal\shortcut\ShortcutSetFormController",
  *       "edit" = "Drupal\shortcut\ShortcutSetFormController",
  *       "customize" = "Drupal\shortcut\Form\SetCustomize",
+ *       "add_link" = "Drupal\shortcut\Form\ShortcutLinkAddForm",
  *       "delete" = "Drupal\shortcut\Form\ShortcutSetDeleteForm"
  *     }
  *   },
@@ -143,4 +144,34 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr
 
     }
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addLink(array $shortcut_link) {
+    // Normalize the path in case it is an alias.
+    $shortcut_link['link_path'] = \Drupal::service('path.alias_manager')->getSystemPath($shortcut_link['link_path']);
+    if (empty($shortcut_link['link_path'])) {
+      $shortcut_link['link_path'] = '<front>';
+    }
+    $menu_link = \Drupal::entityManager()->getStorageController('menu_link')->create($shortcut_link);
+    $menu_link->save();
+
+    // Add the link to the end of the list.
+    $this->links[$menu_link->uuid()] = $menu_link;
+    $this->resetLinkWeights();
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function resetLinkWeights() {
+    $weight = -50;
+    foreach ($this->links as $menu_link) {
+      $menu_link->weight = ++$weight;
+    }
+    return $this;
+  }
+
 }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetAccessController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetAccessController.php
index 3c56353..6a15859 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetAccessController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetAccessController.php
@@ -40,4 +40,13 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+    if ($account->hasPermission('administer shortcuts') || $account->hasPermission('customize shortcut links')) {
+      return TRUE;
+    }
+  }
+
 }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetInterface.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetInterface.php
index d2849fc..cde5d06 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetInterface.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetInterface.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\shortcut\Plugin\Core\Entity\ShortcutSetInterface.
+ * Contains \Drupal\shortcut\ShortcutSetInterface.
  */
 
 namespace Drupal\shortcut;
@@ -14,4 +14,27 @@
  */
 interface ShortcutSetInterface extends ConfigEntityInterface {
 
+  /**
+   * Adds a link to the end of a shortcut set, keeping within a prescribed limit.
+   *
+   * @param array $shortcut_link
+   *   An array representing a shortcut link.
+   *
+   * @return self
+   *   The shortcut set.
+   */
+  public function addLink(array $shortcut_link);
+
+  /**
+   * Resets the link weights in a shortcut set to match their current order.
+   *
+   * This function can be used, for example, when a new shortcut link is added
+   * to the set. If the link is added to the end of the array and this function
+   * is called, it will force that link to display at the end of the list.
+   *
+   * @return self
+   *   The shortcut set.
+   */
+  public function resetLinkWeights();
+
 }
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index b406787..be0f2ca 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -5,9 +5,6 @@
  * Administrative page callbacks for the shortcut module.
  */
 
-use Symfony\Component\HttpFoundation\RedirectResponse;
-use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-
 /**
  * Form callback: builds the form for switching shortcut sets.
  *
@@ -170,178 +167,3 @@ function shortcut_set_switch_submit($form, &$form_state) {
   // Assign the shortcut set to the provided user account.
   shortcut_set_assign_user($set, $account);
 }
-
-/**
- * Form callback: builds the form for adding a new shortcut link.
- *
- * @param $form
- *   An associative array containing the structure of the form.
- * @param $form_state
- *   An associative array containing the current state of the form.
- * @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut
- *   An object representing the shortcut set to which the link will be added.
- *
- * @return
- *   An array representing the form definition.
- *
- * @ingroup forms
- * @see shortcut_link_edit_validate()
- * @see shortcut_link_add_submit()
- */
-function shortcut_link_add($form, &$form_state, $shortcut_set) {
-  drupal_set_title(t('Add new shortcut'));
-  $form['shortcut_set'] = array(
-    '#type' => 'value',
-    '#value' => $shortcut_set,
-  );
-  $form += _shortcut_link_form_elements();
-  return $form;
-}
-
-/**
- * Form callback: builds the form for editing a shortcut link.
- *
- * @param $form
- *   An associative array containing the structure of the form.
- * @param $form_state
- *   An associative array containing the current state of the form.
- * @param $shortcut_link
- *   An array representing the link that is being edited.
- *
- * @return
- *   An array representing the form definition.
- *
- * @ingroup forms
- * @see shortcut_link_edit_validate()
- * @see shortcut_link_edit_submit()
- */
-function shortcut_link_edit($form, &$form_state, $shortcut_link) {
-  drupal_set_title(t('Editing @shortcut', array('@shortcut' => $shortcut_link['link_title'])));
-  $form['original_shortcut_link'] = array(
-    '#type' => 'value',
-    '#value' => $shortcut_link,
-  );
-  $form += _shortcut_link_form_elements($shortcut_link);
-  return $form;
-}
-
-/**
- * Helper function for building a form for adding or editing shortcut links.
- *
- * @param $shortcut_link
- *   (optional) An array representing the shortcut link that will be edited. If
- *   not provided, a new link will be created.
- *
- * @return
- *   An array of form elements.
- */
-function _shortcut_link_form_elements($shortcut_link = NULL) {
-  if (!isset($shortcut_link)) {
-    $shortcut_link = entity_create('menu_link', array(
-      'link_title' => '',
-      'link_path' => ''
-    ));
-  }
-  else {
-    $shortcut_link['link_path'] = ($shortcut_link['link_path'] == '<front>') ? '' : Drupal::service('path.alias_manager')->getPathAlias($shortcut_link['link_path']);
-  }
-
-  $form['shortcut_link']['#tree'] = TRUE;
-  $form['shortcut_link']['link_title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Name'),
-    '#size' => 40,
-    '#maxlength' => 255,
-    '#default_value' => $shortcut_link['link_title'],
-    '#required' => TRUE,
-  );
-
-  $form['shortcut_link']['link_path'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Path'),
-    '#size' => 40,
-    '#maxlength' => 255,
-    '#field_prefix' => url(NULL, array('absolute' => TRUE)),
-    '#default_value' => $shortcut_link['link_path'],
-  );
-
-  $form['#validate'][] = 'shortcut_link_edit_validate';
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-  );
-
-  return $form;
-}
-
-/**
- * Validation handler for the shortcut link add and edit forms.
- */
-function shortcut_link_edit_validate($form, &$form_state) {
-  if (!shortcut_valid_link($form_state['values']['shortcut_link']['link_path'])) {
-    form_set_error('shortcut_link][link_path', t('The link must correspond to a valid path on the site.'));
-  }
-}
-
-/**
- * Submit handler for shortcut_link_edit().
- */
-function shortcut_link_edit_submit($form, &$form_state) {
-  // Normalize the path in case it is an alias.
-  $shortcut_path = Drupal::service('path.alias_manager')->getSystemPath($form_state['values']['shortcut_link']['link_path']);
-  if (empty($shortcut_path)) {
-    $shortcut_path = '<front>';
-  }
-  $form_state['values']['shortcut_link']['link_path'] = $shortcut_path;
-
-  $shortcut_link = $form_state['values']['original_shortcut_link'];
-  foreach ($form_state['values']['shortcut_link'] as $key => $value) {
-   $shortcut_link[$key] = $value;
-  }
-
-  menu_link_save($shortcut_link);
-  $set_name = str_replace('shortcut-', '' , $shortcut_link['menu_name']);
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set_name;
-  drupal_set_message(t('The shortcut %link has been updated.', array('%link' => $shortcut_link['link_title'])));
-}
-
-/**
- * Submit handler for shortcut_link_add().
- */
-function shortcut_link_add_submit($form, &$form_state) {
-  // Add the shortcut link to the set.
-  $shortcut_set = $form_state['values']['shortcut_set'];
-  $shortcut_link = $form_state['values']['shortcut_link'];
-  $shortcut_link['menu_name'] = $shortcut_set->id();
-  shortcut_admin_add_link($shortcut_link, $shortcut_set);
-  $shortcut_set->save();
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id();
-  drupal_set_message(t('Added a shortcut for %title.', array('%title' => $shortcut_link['link_title'])));
-}
-
-/**
- * Adds a link to the end of a shortcut set, keeping within a prescribed limit.
- *
- * @param $link
- *   An array representing a shortcut link.
- * @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut
- *   An object representing the shortcut set which the link will be added to.
- *   The links in the shortcut set will be re-weighted so that the new link is
- *   at the end, and some existing links may be disabled (if the $limit
- *   parameter is provided).
- */
-function shortcut_admin_add_link($shortcut_link, &$shortcut_set) {
-  // Normalize the path in case it is an alias.
-  $shortcut_link['link_path'] = Drupal::service('path.alias_manager')->getSystemPath($shortcut_link['link_path']);
-  if (empty($shortcut_link['link_path'])) {
-    $shortcut_link['link_path'] = '<front>';
-  }
-  $menu_link = entity_create('menu_link', $shortcut_link);
-  $menu_link->save();
-
-  // Add the link to the end of the list.
-  $shortcut_set->links[$menu_link->uuid()] = $menu_link;
-  shortcut_set_reset_link_weights($shortcut_set);
-}
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index c22c97f..07d455c 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -5,8 +5,6 @@
  * Allows users to manage customizable lists of shortcut links.
  */
 
-use Drupal\shortcut\Plugin\Core\Entity\Shortcut;
-
 /**
  * Implements hook_help().
  */
@@ -116,20 +114,12 @@ function shortcut_menu() {
   );
   $items['admin/config/user-interface/shortcut/manage/%shortcut_set/add-link'] = array(
     'title' => 'Add shortcut',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_link_add', 5),
-    'access callback' => 'shortcut_set_edit_access',
-    'access arguments' => array(5),
+    'route_name' => 'shortcut_link_add',
     'type' => MENU_LOCAL_ACTION,
-    'file' => 'shortcut.admin.inc',
   );
   $items['admin/config/user-interface/shortcut/link/%menu_link'] = array(
     'title' => 'Edit shortcut',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_link_edit', 5),
-    'access callback' => 'shortcut_link_access',
-    'access arguments' => array(5),
-    'file' => 'shortcut.admin.inc',
+    'route_name' => 'shortcut_link_edit',
   );
   $items['admin/config/user-interface/shortcut/link/%menu_link/delete'] = array(
     'title' => 'Delete shortcut',
@@ -159,26 +149,10 @@ function shortcut_admin_paths() {
 }
 
 /**
- * Access callback for editing a shortcut set.
- *
- * @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut
- *   (optional) The shortcut set to be edited. If not set, the current user's
- *   shortcut set will be used.
- *
- * @return
- *   TRUE if the current user has access to edit the shortcut set, FALSE
- *   otherwise.
+ * Implements hook_entity_info().
  */
-function shortcut_set_edit_access($shortcut_set = NULL) {
-  // Sufficiently-privileged users can edit their currently displayed shortcut
-  // set, but not other sets. Shortcut administrators can edit any set.
-  if (user_access('administer shortcuts')) {
-    return TRUE;
-  }
-  if (user_access('customize shortcut links')) {
-    return !isset($shortcut_set) || $shortcut_set == shortcut_current_displayed_set();
-  }
-  return FALSE;
+function shortcut_entity_info(&$entity_info) {
+  $entity_info['menu_link']['controllers']['form']['edit_shortcut_link'] = 'Drupal\shortcut\Form\ShortcutLinkEditForm';
 }
 
 /**
@@ -216,19 +190,6 @@ function shortcut_set_switch_access($account = NULL) {
 }
 
 /**
- * Access callback for editing a link in a shortcut set.
- */
-function shortcut_link_access($menu_link) {
-  // The link must belong to a shortcut set that the current user has access
-  // to edit.
-  $set_name = str_replace('shortcut-', '', $menu_link['menu_name']);
-  if ($shortcut_set = shortcut_set_load($set_name)) {
-    return shortcut_set_edit_access($shortcut_set);
-  }
-  return FALSE;
-}
-
-/**
  * Implements hook_menu_link_delete().
  */
 function shortcut_menu_link_delete($menu_link) {
@@ -455,7 +416,7 @@ function shortcut_preprocess_page(&$variables) {
   // shortcuts and if the page's actual content is being shown (for example,
   // we do not want to display it on "access denied" or "page not found"
   // pages).
-  if (shortcut_set_edit_access() && ($item = menu_get_item()) && $item['access']) {
+  if (entity_page_create_access('shortcut_set') && ($item = menu_get_item()) && $item['access']) {
     $link = current_path();
     $query_parameters = drupal_get_query_parameters();
     if (!empty($query_parameters)) {
@@ -516,7 +477,7 @@ function shortcut_toolbar() {
   $links = shortcut_renderable_links();
   $shortcut_set = shortcut_current_displayed_set();
   $configure_link = NULL;
-  if (shortcut_set_edit_access($shortcut_set)) {
+  if ($shortcut_set->access('update')) {
     $configure_link = array(
       '#type' => 'link',
       '#title' => t('Edit shortcuts'),
diff --git a/core/modules/shortcut/shortcut.routing.yml b/core/modules/shortcut/shortcut.routing.yml
index faf495a..76fd544 100644
--- a/core/modules/shortcut/shortcut.routing.yml
+++ b/core/modules/shortcut/shortcut.routing.yml
@@ -3,7 +3,7 @@ shortcut_link_delete:
   defaults:
     _form: 'Drupal\shortcut\Form\LinkDelete'
   requirements:
-    _access_shortcut_link_delete: 'TRUE'
+    _access_shortcut_link_update: 'TRUE'
 
 shortcut_set_delete:
   pattern: '/admin/config/user-interface/shortcut/manage/{shortcut_set}/delete'
@@ -33,6 +33,20 @@ shortcut_set_edit:
   requirements:
     _entity_access: 'shortcut_set.update'
 
+shortcut_link_add:
+  pattern: '/admin/config/user-interface/shortcut/manage/{shortcut_set}/add-link'
+  defaults:
+    _entity_form: 'shortcut_set.add_link'
+  requirements:
+    _entity_access: 'shortcut_set.update'
+
+shortcut_link_edit:
+  pattern: '/admin/config/user-interface/shortcut/link/{menu_link}'
+  defaults:
+    _entity_form: 'menu_link.edit_shortcut_link'
+  requirements:
+    _access_shortcut_link_update: 'TRUE'
+
 shortcut_link_add_inline:
   pattern: '/admin/config/user-interface/shortcut/manage/{shortcut_set}/add-link-inline'
   defaults:
diff --git a/core/modules/shortcut/shortcut.services.yml b/core/modules/shortcut/shortcut.services.yml
index bb95f49..ba52e71 100644
--- a/core/modules/shortcut/shortcut.services.yml
+++ b/core/modules/shortcut/shortcut.services.yml
@@ -1,5 +1,6 @@
 services:
   access_check.shortcut.link:
-    class: Drupal\shortcut\Access\LinkDeleteAccessCheck
+    class: Drupal\shortcut\Access\ShortcutLinkUpdateAccessCheck
+    arguments: ['@plugin.manager.entity']
     tags:
       - { name: access_check }
