diff --git a/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
index f7dbc50..887fcae 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
@@ -118,4 +118,12 @@ public function save(array $form, FormStateInterface $form_state) {}
    */
   public function delete(array $form, FormStateInterface $form_state) {}
 
+  /**
+   * {@inheritdoc}
+   */
+  public function validate(array $form, FormStateInterface $form_state) {
+    // Override the default validation implementation as it is not necessary
+    // nor possible to validate an entity in a confirmation form.
+  }
+
 }
diff --git a/core/modules/link/src/LinkItemInterface.php b/core/modules/link/src/LinkItemInterface.php
index f494e08..b78a05f 100644
--- a/core/modules/link/src/LinkItemInterface.php
+++ b/core/modules/link/src/LinkItemInterface.php
@@ -37,4 +37,11 @@
    */
   public function isExternal();
 
+  /**
+   * Gets the URL object.
+   *
+   * @return \Drupal\Core\Url
+   */
+  public function getUrl();
+
 }
diff --git a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
index 77d733f..d5c1fec 100644
--- a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
+++ b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
@@ -164,4 +164,29 @@ public function isExternal() {
   public static function mainPropertyName() {
     return 'uri';
   }
+
+  /**
+   * Gets the URL object.
+   *
+   * @return \Drupal\Core\Url
+   */
+  public function getUrl() {
+    return \Drupal::pathValidator()->getUrlIfValidWithoutAccessCheck($this->uri);
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Unserialize the values.
+    // @todo The storage controller should take care of this, see
+    //   SqlContentEntityStorage::loadFieldItems, see
+    //   https://www.drupal.org/node/2414835
+    if (isset($values['options']) && is_string($values['options'])) {
+      $values['options'] = unserialize($values['options']);
+    }
+    parent::setValue($values, $notify);
+  }
+
 }
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index f686ea8..7768efe 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\link\Plugin\Field\FieldWidget;
 
+use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
@@ -43,8 +44,9 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     $default_url_value = NULL;
     if (isset($items[$delta]->uri)) {
       if ($url = \Drupal::pathValidator()->getUrlIfValid($items[$delta]->uri)) {
-        $url->setOptions($items[$delta]->options);
-        $default_url_value = ltrim($url->toString(), '/');
+        $url->setOptions($items[$delta]->options ?: []);
+        $url_string = $url->toString();
+        $default_url_value = $url->isRouted() ? Unicode::substr($url_string, strlen(base_path())) : $url_string;
       }
     }
     $element['uri'] = array(
diff --git a/core/modules/shortcut/shortcut.info.yml b/core/modules/shortcut/shortcut.info.yml
index f51d30b..c12bc48 100644
--- a/core/modules/shortcut/shortcut.info.yml
+++ b/core/modules/shortcut/shortcut.info.yml
@@ -5,3 +5,5 @@ package: Core
 version: VERSION
 core: 8.x
 configure: entity.shortcut_set.collection
+dependencies:
+  - link
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index 41a78a2..c1a6883 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -5,9 +5,6 @@
  * Install, update and uninstall functions for the shortcut module.
  */
 
-use Drupal\Core\Database\Database;
-use Drupal\Core\Language\Language;
-
 /**
  * Implements hook_schema().
  */
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index c095934..5f1966c 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -256,10 +256,10 @@ function shortcut_renderable_links($shortcut_set = NULL) {
   $cache_tags = array();
   foreach ($shortcuts as $shortcut) {
     $shortcut = \Drupal::entityManager()->getTranslationFromContext($shortcut);
-    $links[] = array(
+    $links[$shortcut->id()] = array(
+      'type' => 'link',
       'title' => $shortcut->label(),
-      'url' => Url::fromRoute($shortcut->getRouteName(), $shortcut->getRouteParameters()),
-    );
+    ) + $shortcut->getUrl()->toArray();
     $cache_tags = Cache::mergeTags($cache_tags, $shortcut->getCacheTags());
   }
 
@@ -310,8 +310,9 @@ function shortcut_preprocess_page(&$variables) {
 
     // Check if $link is already a shortcut and set $link_mode accordingly.
     $shortcuts = \Drupal::entityManager()->getStorage('shortcut')->loadByProperties(array('shortcut_set' => $shortcut_set->id()));
+    /** @var \Drupal\shortcut\ShortcutInterface $shortcut */
     foreach ($shortcuts as $shortcut) {
-      if ($shortcut->getRouteName() == $route_match->getRouteName() && $shortcut->getRouteParameters() == $route_match->getParameters()->all()) {
+      if (($shortcut_url = $shortcut->getUrl()) && $shortcut_url->isRouted() && $shortcut_url->getRouteName() == $route_match->getRouteName() && $shortcut_url->getRouteParameters() == $route_match->getParameters()->all()) {
         $shortcut_id = $shortcut->id();
         break;
       }
diff --git a/core/modules/shortcut/src/Controller/ShortcutSetController.php b/core/modules/shortcut/src/Controller/ShortcutSetController.php
index 1af8d24..4489964 100644
--- a/core/modules/shortcut/src/Controller/ShortcutSetController.php
+++ b/core/modules/shortcut/src/Controller/ShortcutSetController.php
@@ -64,7 +64,9 @@ public function addShortcutLinkInline(ShortcutSetInterface $shortcut_set, Reques
       $shortcut = $this->entityManager()->getStorage('shortcut')->create(array(
         'title' => $name,
         'shortcut_set' => $shortcut_set->id(),
-        'path' => $link,
+        'link' => array(
+          'uri' => $link,
+        ),
       ));
 
       try {
diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php
index 91a7f0b..f59f77d 100644
--- a/core/modules/shortcut/src/Entity/Shortcut.php
+++ b/core/modules/shortcut/src/Entity/Shortcut.php
@@ -12,13 +12,14 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\Url;
+use Drupal\link\LinkItemInterface;
 use Drupal\shortcut\ShortcutInterface;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Defines the shortcut entity class.
  *
+ * @property \Drupal\link\LinkItemInterface link
+ *
  * @ContentEntityType(
  *   id = "shortcut",
  *   label = @Translation("Shortcut link"),
@@ -65,7 +66,7 @@ public function getTitle() {
    */
   public function setTitle($link_title) {
     $this->set('title', $link_title);
-   return $this;
+    return $this;
   }
 
   /**
@@ -87,67 +88,7 @@ public function setWeight($weight) {
    * {@inheritdoc}
    */
   public function getUrl() {
-    return new Url($this->getRouteName(), $this->getRouteParameters());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRouteName() {
-    return $this->get('route_name')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setRouteName($route_name) {
-    $this->set('route_name', $route_name);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRouteParameters() {
-    return $this->get('route_parameters')->first()->getValue();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setRouteParameters($route_parameters) {
-    $this->set('route_parameters', $route_parameters);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function preCreate(EntityStorageInterface $storage, array &$values) {
-    parent::preCreate($storage, $values);
-
-    if (!isset($values['shortcut_set'])) {
-      $values['shortcut_set'] = 'default';
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSave(EntityStorageInterface $storage) {
-    parent::preSave($storage);
-
-    // @todo fix PathValidatorInterface::getUrlIfValid() so we can use it
-    //   here. The problem is that we need an exception, not a FALSE
-    //   return value. https://www.drupal.org/node/2346695
-    if ($this->path->value == '<front>') {
-      $url = new Url($this->path->value);
-    }
-    else {
-      $url = Url::createFromRequest(Request::create("/{$this->path->value}"));
-    }
-    $this->setRouteName($url->getRouteName());
-    $this->setRouteParameters($url->getRouteParameters());
+    return $this->link->first()->getUrl();
   }
 
   /**
@@ -205,13 +146,22 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('Weight'))
       ->setDescription(t('Weight among shortcuts in the same shortcut set.'));
 
-    $fields['route_name'] = BaseFieldDefinition::create('string')
-      ->setLabel(t('Route name'))
-      ->setDescription(t('The machine name of a defined Route this shortcut represents.'));
-
-    $fields['route_parameters'] = BaseFieldDefinition::create('map')
-      ->setLabel(t('Route parameters'))
-      ->setDescription(t('A serialized array of route parameters of this shortcut.'));
+    $fields['link'] = BaseFieldDefinition::create('link')
+      ->setLabel(t('Path'))
+      ->setDescription(t('The location this shortcut points to.'))
+      ->setRequired(TRUE)
+      ->setTranslatable(FALSE)
+      ->setSettings(array(
+        'default_value' => '',
+        'max_length' => 560,
+        'link_type' => LinkItemInterface::LINK_INTERNAL,
+        'title' => DRUPAL_DISABLED,
+      ))
+      ->setDisplayOptions('form', array(
+        'type' => 'link_default',
+        'weight' => 0,
+      ))
+      ->setDisplayConfigurable('form', TRUE);
 
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
@@ -224,16 +174,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
         'weight' => 2,
       ));
 
-    $fields['path'] = BaseFieldDefinition::create('string')
-      ->setLabel(t('Path'))
-      ->setDescription(t('The computed shortcut path.'))
-      ->setComputed(TRUE)
-      ->setCustomStorage(TRUE);
-
-    $item_definition = $fields['path']->getItemDefinition();
-    $item_definition->setClass('\Drupal\shortcut\ShortcutPathItem');
-    $fields['path']->setItemDefinition($item_definition);
-
     return $fields;
   }
 
diff --git a/core/modules/shortcut/src/Form/SetCustomize.php b/core/modules/shortcut/src/Form/SetCustomize.php
index 2d026b5..e0cf262 100644
--- a/core/modules/shortcut/src/Form/SetCustomize.php
+++ b/core/modules/shortcut/src/Form/SetCustomize.php
@@ -52,7 +52,11 @@ public function form(array $form, FormStateInterface $form_state) {
     foreach ($this->entity->getShortcuts() as $shortcut) {
       $id = $shortcut->id();
       $form['shortcuts']['links'][$id]['#attributes']['class'][] = 'draggable';
-      $form['shortcuts']['links'][$id]['name']['#markup'] = $this->l($shortcut->getTitle(), $shortcut->getUrl());
+      $form['shortcuts']['links'][$id]['name'] = array(
+        '#type' => 'link',
+        '#title' => $shortcut->getTitle(),
+      ) + $shortcut->getUrl()->toRenderArray();
+      unset($form['shortcuts']['links'][$id]['name']['#access_callback']);
       $form['shortcuts']['links'][$id]['#weight'] = $shortcut->getWeight();
       $form['shortcuts']['links'][$id]['weight'] = array(
         '#type' => 'weight',
diff --git a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
index 6d8ec7c..21b74d9 100644
--- a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
+++ b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
@@ -27,7 +27,7 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return $this->t('Are you sure you want to delete the shortcut %title?', array('%title' => $this->entity->title->value));
+    return $this->t('Are you sure you want to delete the shortcut %title?', array('%title' => $this->entity->getTitle()));
   }
 
   /**
diff --git a/core/modules/shortcut/src/ShortcutForm.php b/core/modules/shortcut/src/ShortcutForm.php
index 60796f8..1e1cd37 100644
--- a/core/modules/shortcut/src/ShortcutForm.php
+++ b/core/modules/shortcut/src/ShortcutForm.php
@@ -8,10 +8,7 @@
 namespace Drupal\shortcut;
 
 use Drupal\Core\Entity\ContentEntityForm;
-use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Path\PathValidatorInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Form controller for the shortcut entity forms.
@@ -26,76 +23,6 @@ class ShortcutForm extends ContentEntityForm {
   protected $entity;
 
   /**
-   * The path validator.
-   *
-   * @var \Drupal\Core\Path\PathValidatorInterface
-   */
-  protected $pathValidator;
-
-  /**
-   * Constructs a new ShortcutForm instance.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager
-   * @param \Drupal\Core\Path\PathValidatorInterface $path_validator
-   *   The path validator.
-   */
-  public function __construct(EntityManagerInterface $entity_manager, PathValidatorInterface $path_validator) {
-    parent::__construct($entity_manager);
-
-    $this->pathValidator = $path_validator;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static($container->get('entity.manager'), $container->get('path.validator'));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function form(array $form, FormStateInterface $form_state) {
-    $form = parent::form($form, $form_state);
-
-    $form['path'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Path'),
-      '#size' => 40,
-      '#maxlength' => 255,
-      '#field_prefix' => $this->url('<front>', array(), array('absolute' => TRUE)),
-      '#default_value' => $this->entity->path->value,
-    );
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildEntity(array $form, FormStateInterface $form_state) {
-    $entity = parent::buildEntity($form, $form_state);
-
-    // Set the computed 'path' value so it can used in the preSave() method to
-    // derive the route name and parameters.
-    $entity->path->value = $form_state->getValue('path');
-
-    return $entity;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validate(array $form, FormStateInterface $form_state) {
-    if (!$this->pathValidator->isValid($form_state->getValue('path'))) {
-      $form_state->setErrorByName('path', $this->t('The shortcut must correspond to a valid path on the site.'));
-    }
-
-    parent::validate($form, $form_state);
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
diff --git a/core/modules/shortcut/src/ShortcutInterface.php b/core/modules/shortcut/src/ShortcutInterface.php
index c074b83..5c33a7f 100644
--- a/core/modules/shortcut/src/ShortcutInterface.php
+++ b/core/modules/shortcut/src/ShortcutInterface.php
@@ -60,42 +60,4 @@ public function setWeight($weight);
    */
   public function getUrl();
 
-  /**
-   * Returns the route name associated with this shortcut, if any.
-   *
-   * @return string|null
-   *   The route name of this shortcut.
-   */
-  public function getRouteName();
-
-  /**
-   * Sets the route name associated with this shortcut.
-   *
-   * @param string|null $route_name
-   *   The route name associated with this shortcut.
-   *
-   * @return \Drupal\shortcut\ShortcutInterface
-   *   The called shortcut entity.
-   */
-  public function setRouteName($route_name);
-
-  /**
-   * Returns the route parameters associated with this shortcut, if any.
-   *
-   * @return array
-   *   The route parameters of this shortcut.
-   */
-  public function getRouteParameters();
-
-  /**
-   * Sets the route parameters associated with this shortcut.
-   *
-   * @param array $route_parameters
-   *   The route parameters associated with this shortcut.
-   *
-   * @return \Drupal\shortcut\ShortcutInterface
-   *   The called shortcut entity.
-   */
-  public function setRouteParameters($route_parameters);
-
 }
diff --git a/core/modules/shortcut/src/ShortcutPathItem.php b/core/modules/shortcut/src/ShortcutPathItem.php
deleted file mode 100644
index 7c63a30..0000000
--- a/core/modules/shortcut/src/ShortcutPathItem.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\shortcut\ShortcutPathItem.
- */
-
-namespace Drupal\shortcut;
-
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
-use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
-use Drupal\Core\TypedData\DataDefinition;
-
-/**
- * The field item for the 'path' field.
- */
-class ShortcutPathItem extends StringItem {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
-    $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('String value'))
-      ->setComputed(TRUE)
-      ->setClass('\Drupal\shortcut\ShortcutPathValue')
-      ->setRequired(TRUE);
-    return $properties;
-  }
-
-}
diff --git a/core/modules/shortcut/src/ShortcutPathValue.php b/core/modules/shortcut/src/ShortcutPathValue.php
deleted file mode 100644
index 8d05b7d..0000000
--- a/core/modules/shortcut/src/ShortcutPathValue.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\shortcut\ShortcutPathValue.
- */
-
-namespace Drupal\shortcut;
-
-use Drupal\Core\TypedData\TypedData;
-
-/**
- * A computed property for the string value of the path field.
- */
-class ShortcutPathValue extends TypedData {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValue() {
-    if (!isset($this->value)) {
-      if (!isset($this->parent)) {
-        throw new \InvalidArgumentException('Computed properties require context for computation.');
-      }
-
-      $entity = $this->parent->getEntity();
-      if ($route_name = $entity->getRouteName()) {
-        $path = \Drupal::urlGenerator()->getPathFromRoute($route_name, $entity->getRouteParameters());
-        $this->value = trim($path, '/');
-      }
-      else {
-        $this->value = NULL;
-      }
-    }
-    return $this->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setValue($value, $notify = TRUE) {
-    // Normalize the path in case it is an alias.
-    $value = \Drupal::service('path.alias_manager')->getPathByAlias($value);
-    if (empty($value)) {
-      $value = '<front>';
-    }
-
-    parent::setValue($value, $notify);
-  }
-
-}
diff --git a/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php b/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
index 2fd7385..e116214 100644
--- a/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutCacheTagsTest.php
@@ -43,10 +43,10 @@ protected function setUp() {
   protected function createEntity() {
     // Create a "Llama" shortcut.
     $shortcut = Shortcut::create(array(
-      'set' => 'default',
+      'shortcut_set' => 'default',
       'title' => t('Llama'),
       'weight' => 0,
-      'path' => 'admin',
+      'link' => ['uri' => 'admin'],
     ));
     $shortcut->save();
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
index dd637f1..27202ba 100644
--- a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php
@@ -6,6 +6,9 @@
  */
 
 namespace Drupal\shortcut\Tests;
+
+use Drupal\Component\Utility\String;
+use Drupal\Core\Url;
 use Drupal\shortcut\Entity\Shortcut;
 use Drupal\shortcut\Entity\ShortcutSet;
 
@@ -37,42 +40,40 @@ public function testShortcutLinkAdd() {
     $this->container->get('path.alias_storage')->save($path['source'], $path['alias']);
 
     // Create some paths to test.
-    $test_cases = array(
-      array('path' => '', 'route_name' => '<front>'),
-      array('path' => '<front>', 'route_name' => '<front>'),
-      array('path' => 'admin', 'route_name' => 'system.admin'),
-      array('path' => 'admin/config/system/site-information', 'route_name' => 'system.site_information_settings'),
-      array('path' => 'node/' . $this->node->id() . '/edit', 'route_name' => 'entity.node.edit_form'),
-      array('path' => $path['alias'], 'route_name' => 'entity.node.canonical'),
-      array('path' => 'router_test/test2', 'route_name' => 'router_test.2'),
-      array('path' => 'router_test/test3/value', 'route_name' => 'router_test.3'),
-    );
+    $test_cases = [
+      '<front>',
+      'admin',
+      'admin/config/system/site-information',
+      'node/' . $this->node->id() . '/edit',
+      $path['alias'],
+      'router_test/test2',
+      'router_test/test3/value',
+    ];
 
     // Check that each new shortcut links where it should.
-    foreach ($test_cases as $test) {
+    foreach ($test_cases as $test_path) {
       $title = $this->randomMachineName();
       $form_data = array(
         'title[0][value]' => $title,
-        'path' => $test['path'],
+        'link[0][uri]' => $test_path,
       );
       $this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
       $this->assertResponse(200);
       $saved_set = ShortcutSet::load($set->id());
-      $routes = $this->getShortcutInformation($saved_set, 'route_name');
-      $this->assertTrue(in_array($test['route_name'], $routes), 'Shortcut created: ' . $test['path']);
-      $this->assertLink($title, 0, 'Shortcut link found on the page.');
+      $paths = $this->getShortcutInformation($saved_set, 'link');
+      $test_path = $test_path != '<front>' ? $test_path : '';
+      $this->assertTrue(in_array($test_path, $paths), 'Shortcut created: ' . $test_path);
+      $this->assertLink($title, 0, String::format('Shortcut link %url found on the page.', ['%url' => $test_path]));
     }
     $saved_set = ShortcutSet::load($set->id());
     // Test that saving and re-loading a shortcut preserves its values.
     $shortcuts = $saved_set->getShortcuts();
     foreach ($shortcuts as $entity) {
       // Test the node routes with parameters.
-      if (strpos($entity->route_name->value, 'node.') === 0) {
-        $entity->save();
-        $loaded = Shortcut::load($entity->id());
-        $this->assertEqual($entity->route_name->value, $loaded->route_name->value);
-        $this->assertEqual($entity->get('route_parameters')->first()->getValue(), $loaded->get('route_parameters')->first()->getValue());
-      }
+      $entity->save();
+      $loaded = Shortcut::load($entity->id());
+      $this->assertEqual($entity->link->uri, $loaded->link->uri);
+      $this->assertEqual($entity->link->options, $loaded->link->options);
     }
 
     // Login as non admin user, to check that access is checked when creating
@@ -81,15 +82,15 @@ public function testShortcutLinkAdd() {
     $title = $this->randomMachineName();
     $form_data = [
       'title[0][value]' => $title,
-      'path' => 'admin',
+      'link[0][uri]' => 'admin',
     ];
     $this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
     $this->assertResponse(200);
-    $this->assertRaw(t('The shortcut must correspond to a valid path on the site.'));
+    $this->assertRaw(t('The URL %url is not valid.', ['%url' => 'admin']));
 
     $form_data = [
       'title[0][value]' => $title,
-      'path' => 'node',
+      'link[0][uri]' => 'node',
     ];
     $this->drupalPostForm('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
     $this->assertLink($title, 0, 'Shortcut link found on the page.');
@@ -136,7 +137,7 @@ public function testShortcutLinkRename() {
 
     $shortcuts = $set->getShortcuts();
     $shortcut = reset($shortcuts);
-    $this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $new_link_name, 'path' => $shortcut->path->value), t('Save'));
+    $this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $new_link_name, 'link[0][uri]' => $shortcut->link->uri), t('Save'));
     $saved_set = ShortcutSet::load($set->id());
     $titles = $this->getShortcutInformation($saved_set, 'title');
     $this->assertTrue(in_array($new_link_name, $titles), 'Shortcut renamed: ' . $new_link_name);
@@ -154,10 +155,10 @@ public function testShortcutLinkChangePath() {
 
     $shortcuts = $set->getShortcuts();
     $shortcut = reset($shortcuts);
-    $this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $shortcut->getTitle(), 'path' => $new_link_path), t('Save'));
+    $this->drupalPostForm('admin/config/user-interface/shortcut/link/' . $shortcut->id(), array('title[0][value]' => $shortcut->getTitle(), 'link[0][uri]' => $new_link_path), t('Save'));
     $saved_set = ShortcutSet::load($set->id());
-    $routes = $this->getShortcutInformation($saved_set, 'route_name');
-    $this->assertTrue(in_array('system.admin_config', $routes), 'Shortcut path changed: ' . $new_link_path);
+    $paths = $this->getShortcutInformation($saved_set, 'link');
+    $this->assertTrue(in_array($new_link_path, $paths), 'Shortcut path changed: ' . $new_link_path);
     $this->assertLinkByHref($new_link_path, 0, 'Shortcut with new path appears on the page.');
   }
 
diff --git a/core/modules/shortcut/src/Tests/ShortcutTestBase.php b/core/modules/shortcut/src/Tests/ShortcutTestBase.php
index 966891c..99a092b 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTestBase.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTestBase.php
@@ -62,18 +62,22 @@ protected function setUp() {
 
       // Populate the default shortcut set.
       $shortcut = Shortcut::create(array(
-        'set' => 'default',
+        'shortcut_set' => 'default',
         'title' => t('Add content'),
         'weight' => -20,
-        'path' => 'node/add',
+        'link' => array(
+          'uri' => 'node/add',
+        ),
       ));
       $shortcut->save();
 
       $shortcut = Shortcut::create(array(
-        'set' => 'default',
+        'shortcut_set' => 'default',
         'title' => t('All content'),
         'weight' => -19,
-        'path' => 'admin/content',
+        'link' => array(
+          'uri' => 'admin/content',
+        ),
       ));
       $shortcut->save();
     }
@@ -111,7 +115,7 @@ function generateShortcutSet($label = '', $id = NULL) {
    * @param string $key
    *   The array key indicating what information to extract from each link:
    *    - 'title': Extract shortcut titles.
-   *    - 'path': Extract shortcut paths.
+   *    - 'link': Extract shortcut paths.
    *    - 'id': Extract the shortcut ID.
    *
    * @return array
@@ -121,7 +125,12 @@ function getShortcutInformation(ShortcutSetInterface $set, $key) {
     $info = array();
     \Drupal::entityManager()->getStorage('shortcut')->resetCache();
     foreach ($set->getShortcuts() as $shortcut) {
-      $info[] = $shortcut->{$key}->value;
+      if ($key == 'link') {
+        $info[] = $shortcut->link->uri;
+      }
+      else {
+        $info[] = $shortcut->{$key}->value;
+      }
     }
     return $info;
   }
diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
index 453e465..2944e1f 100644
--- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
+++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php
@@ -25,6 +25,7 @@ class ShortcutTranslationUITest extends ContentTranslationUITest {
   public static $modules = array(
     'language',
     'content_translation',
+    'link',
     'shortcut',
     'toolbar'
   );
@@ -49,7 +50,7 @@ protected function getTranslatorPermissions() {
    * {@inheritdoc}
    */
   protected function createEntity($values, $langcode, $bundle_name = NULL) {
-    $values['route_name'] = 'user.page';
+    $values['link']['uri'] = 'user';
     return parent::createEntity($values, $langcode, $bundle_name);
   }
 
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index f571667..085b561 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -58,7 +58,7 @@ function standard_install() {
     'shortcut_set' => 'default',
     'title' => t('Add content'),
     'weight' => -20,
-    'path' => 'node/add',
+    'link' => array('uri' => 'node/add'),
   ));
   $shortcut->save();
 
@@ -66,7 +66,7 @@ function standard_install() {
     'shortcut_set' => 'default',
     'title' => t('All content'),
     'weight' => -19,
-    'path' => 'admin/content',
+    'link' => array('uri' => 'admin/content'),
   ));
   $shortcut->save();
 
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index a93226a..cea8770 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -37,6 +37,13 @@ class UrlTest extends UnitTestCase {
   protected $urlGenerator;
 
   /**
+   * The path alias manager.
+   *
+   * @var \Drupal\Core\Path\AliasManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $pathAliasManager;
+
+  /**
    * The router.
    *
    * @var \Drupal\Tests\Core\Routing\TestRouterInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -62,15 +69,31 @@ protected function setUp() {
     $map[] = array('node_edit', array('node' => '2'), array(), '/node/2/edit');
     $this->map = $map;
 
+    $alias_map = array(
+      // Set up one proper alias that can be resolved to a system path.
+      array('node-alias-test', NULL, 'node'),
+      // Passing in anything else should return the same string.
+      array('node', NULL, 'node'),
+      array('node/1', NULL, 'node/1'),
+      array('node/2/edit', NULL, 'node/2/edit'),
+      array('non-existent', NULL, 'non-existent'),
+    );
+
     $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
     $this->urlGenerator->expects($this->any())
       ->method('generateFromRoute')
       ->will($this->returnValueMap($this->map));
 
+    $this->pathAliasManager = $this->getMock('Drupal\Core\Path\AliasManagerInterface');
+    $this->pathAliasManager->expects($this->any())
+      ->method('getPathByAlias')
+      ->will($this->returnValueMap($alias_map));
+
     $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface');
     $this->container = new ContainerBuilder();
     $this->container->set('router.no_access_checks', $this->router);
     $this->container->set('url_generator', $this->urlGenerator);
+    $this->container->set('path.alias_manager', $this->pathAliasManager);
     \Drupal::setContainer($this->container);
   }
 
