diff --git a/core/modules/shortcut/config/shortcut.set.default.yml b/core/modules/shortcut/config/shortcut.set.default.yml
new file mode 100644
index 0000000..3e50e3b
--- /dev/null
+++ b/core/modules/shortcut/config/shortcut.set.default.yml
@@ -0,0 +1,2 @@
+id: default
+label: Default
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php
new file mode 100644
index 0000000..55200e7
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Plugin/Core/Entity/Shortcut.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\shortcut\Plugin\Core\Entity\Shortcut.
+ */
+
+namespace Drupal\shortcut\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the Shortcut configuration entity.
+ *
+ * @Plugin(
+ *   id = "shortcut",
+ *   label = @Translation("Shortcut"),
+ *   module = "shortcut",
+ *   controller_class = "Drupal\shortcut\ShortcutStorageController",
+ *   list_controller_class = "Drupal\shortcut\ShortcutListController",
+ *   uri_callback = "shortcut_uri",
+ *   config_prefix = "shortcut.set",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class Shortcut extends ConfigEntityBase {
+
+  /**
+   * The machine name for the configuration entity.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The UUID for the configuration entity.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The human-readable name of the configuration entity.
+   *
+   * @var string
+   */
+  public $label;
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php
new file mode 100644
index 0000000..579a7d9
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutFormController.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\shortcut\ShortcutFormController.
+ */
+
+namespace Drupal\shortcut;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the test entity edit forms.
+ */
+class ShortcutFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $entity) {
+    $form = parent::form($form, $form_state, $entity);
+
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Set name'),
+      '#description' => t('The new set is created by copying items from your default shortcut set.'),
+      '#required' => TRUE,
+      '#default_value' => $entity->label(),
+    );
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#machine_name' => array(
+        'exists' => 'shortcut_set_load',
+        'source' => array('label'),
+        'replace_pattern' => '[^a-z0-9-]+',
+        'replace' => '-',
+      ),
+      '#default_value' => $entity->id(),
+      '#disabled' => !$entity->isNew(),
+      // This id could be used for menu name.
+      '#maxlength' => 23,
+    );
+
+    $form['actions']['submit']['#value'] = t('Create new set');
+
+    return $form;
+  }
+
+  /**
+   * Returns an array of supported actions for the current entity form.
+   */
+  protected function actions(array $form, array &$form_state) {
+    // Disable delete of default shortcut set.
+    $actions = parent::actions($form, $form_state);
+    $actions['delete']['#access'] = shortcut_set_delete_access($this->getEntity($form_state));
+    return $actions;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+    $entity = $this->getEntity($form_state);
+    // Check to prevent a duplicate title.
+    if ($form_state['values']['label'] != $entity->label() && shortcut_set_title_exists($form_state['values']['label'])) {
+      form_set_error('label', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['label'])));
+    }
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $entity = $this->getEntity($form_state);
+    $is_new = !$entity->getOriginalID();
+    $entity->save();
+
+    if ($is_new) {
+      drupal_set_message(t('The %set_name shortcut set has been created. You can edit it from this page.', array('%set_name' => $entity->label())));
+    }
+    else {
+      drupal_set_message(t('Updated set name to %set-name.', array('%set-name' => $entity->label())));
+    }
+    $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $entity->id();
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::delete().
+   */
+  public function delete(array $form, array &$form_state) {
+    $entity = $this->getEntity($form_state);
+    $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $entity->id() . '/delete';
+  }
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php
new file mode 100644
index 0000000..140525d
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * Definition of Drupal\shortcut\ShortcutListController.
+ */
+
+namespace Drupal\shortcut;
+
+use Drupal\Core\Config\Entity\ConfigEntityListController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of contact categories.
+ */
+class ShortcutListController extends ConfigEntityListController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildHeader().
+   */
+  public function buildHeader() {
+    $row['label'] = t('Name');
+    $row['operations'] = t('Operations');
+    return $row;
+  }
+
+  /**
+   * Implements Drupal\Core\Entity\EntityListController::getOperations().
+   */
+  public function getOperations(EntityInterface $entity) {
+    $uri = $entity->uri();
+    $operations['list'] = array(
+      'title' => t('list links'),
+      'href' => $uri['path'],
+    );
+    $operations['edit'] = array(
+      'title' => t('edit set'),
+      'href' => $uri['path'] . '/edit',
+      'options' => $uri['options'],
+      'weight' => 10,
+    );
+    if (shortcut_set_delete_access($entity)) {
+      $operations['delete'] = array(
+        'title' => t('delete set'),
+        'href' => $uri['path'] . '/delete',
+        'options' => $uri['options'],
+        'weight' => 100,
+      );
+    }
+    return $operations;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildRow().
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['name'] = check_plain($entity->label());
+    $row['operations']['data'] = $this->buildOperations($entity);
+    return $row;
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutStorageController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutStorageController.php
new file mode 100644
index 0000000..25eca58
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutStorageController.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\shortcut\ShortcutStorageController.
+ */
+
+namespace Drupal\shortcut;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a storage controller for shortcut entities.
+ */
+class ShortcutStorageController extends ConfigStorageController {
+
+  /**
+   * Overrides Drupal\config\ConfigStorageController::save().
+   */
+  public function save(EntityInterface $entity) {
+    // Generate menu-compatible set name.
+    if (!$entity->getOriginalID()) {
+      // Save a new shortcut set with links copied from the user's default set.
+      $default_set = shortcut_default_set();
+      // Generate a name to have no collisions with menu.
+      // Size of menu_name is 32 so id could be 23 = 32 - strlen('shortcut-').
+      $id = substr($entity->id(), 0, 23);
+      $entity->set('id', $id);
+      $entity->set('links', menu_links_clone($default_set->links, $id));
+    }
+    parent::save($entity);
+  }
+
+  /**
+   * Overrides Drupal\config\ConfigStorageController::postSave().
+   */
+  function postSave(EntityInterface $entity, $update) {
+    // Process links in shortcut set.
+    // If links were provided for the set, save them.
+    if (isset($entity->links)) {
+      foreach ($entity->links as &$link) {
+        // Do not specifically associate these links with the shortcut module,
+        // since other modules may make them editable via the menu system.
+        // However, we do need to specify the correct menu name.
+        $link['menu_name'] = 'shortcut-' . $entity->id();
+        $link['plid'] = 0;
+        menu_link_save($link);
+      }
+      // Make sure that we have a return value, since if the links were updated
+      // but the shortcut set was not, the call to drupal_write_record() above
+      // would not return an indication that anything had changed.
+      return SAVED_UPDATED;
+    }
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\DatabaseStorageController::preDelete().
+   */
+  protected function preDelete($entities) {
+    foreach ($entities as $entity) {
+      // First, delete any user assignments for this set, so that each of these
+      // users will go back to using whatever default set applies.
+      db_delete('shortcut_set_users')
+        ->condition('set_name', $entity->id())
+        ->execute();
+
+      // Next, delete the menu links for this set.
+      menu_delete_links('shortcut-' . $entity->id());
+    }
+  }
+
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
index 54eeab4..9e118b5 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
@@ -44,14 +44,14 @@ function testShortcutLinkAdd() {
 
     // Check that each new shortcut links where it should.
     foreach ($test_cases as $test) {
-      $title = $this->randomName(10);
+      $title = $this->randomName();
       $form_data = array(
         'shortcut_link[link_title]' => $title,
         'shortcut_link[link_path]'  => $test['path'],
       );
-      $this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/add-link', $form_data, t('Save'));
+      $this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/add-link', $form_data, t('Save'));
       $this->assertResponse(200);
-      $saved_set = shortcut_set_load($set->set_name);
+      $saved_set = shortcut_set_load($set->id());
       $paths = $this->getShortcutInformation($saved_set, 'link_path');
       $test_path = empty($test['path']) ? '<front>' : $test['path'];
       $this->assertTrue(in_array(drupal_get_normal_path($test_path), $paths), 'Shortcut created: '. $test['path']);
@@ -67,7 +67,7 @@ function testShortcutQuickLink() {
     variable_set('admin_theme', 'seven');
     variable_set('node_admin_theme', TRUE);
     $this->drupalGet($this->set->links[0]['link_path']);
-    $this->assertRaw(t('Remove from %title shortcuts', array('%title' => $this->set->title)), '"Add to shortcuts" link properly switched to "Remove from shortcuts".');
+    $this->assertRaw(t('Remove from %title shortcuts', array('%title' => $this->set->label())), '"Add to shortcuts" link properly switched to "Remove from shortcuts".');
   }
 
   /**
@@ -77,10 +77,10 @@ function testShortcutLinkRename() {
     $set = $this->set;
 
     // Attempt to rename shortcut link.
-    $new_link_name = $this->randomName(10);
+    $new_link_name = $this->randomName();
 
     $this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'], array('shortcut_link[link_title]' => $new_link_name, 'shortcut_link[link_path]' => $set->links[0]['link_path']), t('Save'));
-    $saved_set = shortcut_set_load($set->set_name);
+    $saved_set = shortcut_set_load($set->id());
     $titles = $this->getShortcutInformation($saved_set, 'link_title');
     $this->assertTrue(in_array($new_link_name, $titles), 'Shortcut renamed: ' . $new_link_name);
     $this->assertLink($new_link_name, 0, 'Renamed shortcut link appears on the page.');
@@ -96,7 +96,7 @@ function testShortcutLinkChangePath() {
     $new_link_path = 'admin/config';
 
     $this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'], array('shortcut_link[link_title]' => $set->links[0]['link_title'], 'shortcut_link[link_path]' => $new_link_path), t('Save'));
-    $saved_set = shortcut_set_load($set->set_name);
+    $saved_set = shortcut_set_load($set->id());
     $paths = $this->getShortcutInformation($saved_set, 'link_path');
     $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.');
@@ -109,7 +109,7 @@ function testShortcutLinkDelete() {
     $set = $this->set;
 
     $this->drupalPost('admin/config/user-interface/shortcut/link/' . $set->links[0]['mlid'] . '/delete', array(), 'Delete');
-    $saved_set = shortcut_set_load($set->set_name);
+    $saved_set = shortcut_set_load($set->id());
     $mlids = $this->getShortcutInformation($saved_set, 'mlid');
     $this->assertFalse(in_array($set->links[0]['mlid'], $mlids), 'Successfully deleted a shortcut.');
   }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutSetsTest.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutSetsTest.php
index 9efc6ce..c5df40f 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutSetsTest.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutSetsTest.php
@@ -26,36 +26,36 @@ public static function getInfo() {
    * Tests creating a shortcut set.
    */
   function testShortcutSetAdd() {
-    $new_set = $this->generateShortcutSet($this->randomName(10));
-    $sets = shortcut_sets();
-    $this->assertTrue(isset($sets[$new_set->set_name]), 'Successfully created a shortcut set.');
+    $new_set = $this->generateShortcutSet($this->randomName());
+    $sets = entity_load_multiple('shortcut');
+    $this->assertTrue(isset($sets[$new_set->id()]), 'Successfully created a shortcut set.');
     $this->drupalGet('user/' . $this->admin_user->uid . '/shortcuts');
-    $this->assertText($new_set->title, 'Generated shortcut set was listed as a choice on the user account page.');
+    $this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
   }
 
   /**
    * Tests switching a user's own shortcut set.
    */
   function testShortcutSetSwitchOwn() {
-    $new_set = $this->generateShortcutSet($this->randomName(10));
+    $new_set = $this->generateShortcutSet($this->randomName());
 
     // Attempt to switch the default shortcut set to the newly created shortcut
     // set.
-    $this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', array('set' => $new_set->set_name), t('Change set'));
+    $this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', array('set' => $new_set->id()), t('Change set'));
     $this->assertResponse(200);
     $current_set = shortcut_current_displayed_set($this->admin_user);
-    $this->assertTrue($new_set->set_name == $current_set->set_name, 'Successfully switched own shortcut set.');
+    $this->assertTrue($new_set->id() == $current_set->id(), 'Successfully switched own shortcut set.');
   }
 
   /**
    * Tests switching another user's shortcut set.
    */
   function testShortcutSetAssign() {
-    $new_set = $this->generateShortcutSet($this->randomName(10));
+    $new_set = $this->generateShortcutSet($this->randomName());
 
     shortcut_set_assign_user($new_set, $this->shortcut_user);
     $current_set = shortcut_current_displayed_set($this->shortcut_user);
-    $this->assertTrue($new_set->set_name == $current_set->set_name, "Successfully switched another user's shortcut set.");
+    $this->assertTrue($new_set->id() == $current_set->id(), "Successfully switched another user's shortcut set.");
   }
 
   /**
@@ -64,12 +64,13 @@ function testShortcutSetAssign() {
   function testShortcutSetSwitchCreate() {
     $edit = array(
       'set' => 'new',
-      'new' => $this->randomName(10),
+      'id' => strtolower($this->randomName()),
+      'label' => $this->randomString(),
     );
     $this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', $edit, t('Change set'));
     $current_set = shortcut_current_displayed_set($this->admin_user);
-    $this->assertNotEqual($current_set->set_name, $this->set->set_name, 'A shortcut set can be switched to at the same time as it is created.');
-    $this->assertEqual($current_set->title, $edit['new'], 'The new set is correctly assigned to the user.');
+    $this->assertNotEqual($current_set->id(), $this->set->id(), 'A shortcut set can be switched to at the same time as it is created.');
+    $this->assertEqual($current_set->label(), $edit['label'], 'The new set is correctly assigned to the user.');
   }
 
   /**
@@ -78,24 +79,24 @@ function testShortcutSetSwitchCreate() {
   function testShortcutSetSwitchNoSetName() {
     $edit = array('set' => 'new');
     $this->drupalPost('user/' . $this->admin_user->uid . '/shortcuts', $edit, t('Change set'));
-    $this->assertText(t('The new set name is required.'));
+    $this->assertText(t('The new set label is required.'));
     $current_set = shortcut_current_displayed_set($this->admin_user);
-    $this->assertEqual($current_set->set_name, $this->set->set_name, 'Attempting to switch to a new shortcut set without providing a set name does not succeed.');
+    $this->assertEqual($current_set->id(), $this->set->id(), 'Attempting to switch to a new shortcut set without providing a set name does not succeed.');
   }
 
   /**
-   * Tests that shortcut_set_save() correctly updates existing links.
+   * Tests that save() correctly updates existing links.
    */
   function testShortcutSetSave() {
     $set = $this->set;
     $old_mlids = $this->getShortcutInformation($set, 'mlid');
 
-    $set->links[] = $this->generateShortcutLink('admin', $this->randomName(10));
-    shortcut_set_save($set);
-    $saved_set = shortcut_set_load($set->set_name);
+    $set->links[] = $this->generateShortcutLink('admin', $this->randomName());
+    $set->save();
+    $saved_set = shortcut_set_load($set->id());
 
     $new_mlids = $this->getShortcutInformation($saved_set, 'mlid');
-    $this->assertTrue(count(array_intersect($old_mlids, $new_mlids)) == count($old_mlids), 'shortcut_set_save() did not inadvertently change existing mlids.');
+    $this->assertTrue(count(array_intersect($old_mlids, $new_mlids)) == count($old_mlids), 'Shortcut::save() did not inadvertently change existing mlids.');
   }
 
   /**
@@ -104,53 +105,53 @@ function testShortcutSetSave() {
   function testShortcutSetRename() {
     $set = $this->set;
 
-    $new_title = $this->randomName(10);
-    $this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/edit', array('title' => $new_title), t('Save'));
-    $set = shortcut_set_load($set->set_name);
-    $this->assertTrue($set->title == $new_title, 'Shortcut set has been successfully renamed.');
+    $new_label = $this->randomName();
+    $this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/edit', array('label' => $new_label), t('Save'));
+    $set = shortcut_set_load($set->id());
+    $this->assertTrue($set->label() == $new_label, 'Shortcut set has been successfully renamed.');
   }
 
   /**
    * Tests renaming a shortcut set to the same name as another set.
    */
   function testShortcutSetRenameAlreadyExists() {
-    $set = $this->generateShortcutSet($this->randomName(10));
-    $existing_title = $this->set->title;
-    $this->drupalPost('admin/config/user-interface/shortcut/' . $set->set_name . '/edit', array('title' => $existing_title), t('Save'));
-    $this->assertRaw(t('The shortcut set %name already exists. Choose another name.', array('%name' => $existing_title)));
-    $set = shortcut_set_load($set->set_name);
-    $this->assertNotEqual($set->title, $existing_title, format_string('The shortcut set %title cannot be renamed to %new-title because a shortcut set with that title already exists.', array('%title' => $set->title, '%new-title' => $existing_title)));
+    $set = $this->generateShortcutSet($this->randomName());
+    $existing_label = $this->set->label();
+    $this->drupalPost('admin/config/user-interface/shortcut/manage/' . $set->id() . '/edit', array('label' => $existing_label), t('Save'));
+    $this->assertRaw(t('The shortcut set %name already exists. Choose another name.', array('%name' => $existing_label)));
+    $set = shortcut_set_load($set->id());
+    $this->assertNotEqual($set->label(), $existing_label, format_string('The shortcut set %title cannot be renamed to %new-title because a shortcut set with that title already exists.', array('%title' => $set->label(), '%new-title' => $existing_label)));
   }
 
   /**
    * Tests unassigning a shortcut set.
    */
   function testShortcutSetUnassign() {
-    $new_set = $this->generateShortcutSet($this->randomName(10));
+    $new_set = $this->generateShortcutSet($this->randomName());
 
     shortcut_set_assign_user($new_set, $this->shortcut_user);
     shortcut_set_unassign_user($this->shortcut_user);
     $current_set = shortcut_current_displayed_set($this->shortcut_user);
     $default_set = shortcut_default_set($this->shortcut_user);
-    $this->assertTrue($current_set->set_name == $default_set->set_name, "Successfully unassigned another user's shortcut set.");
+    $this->assertTrue($current_set->id() == $default_set->id(), "Successfully unassigned another user's shortcut set.");
   }
 
   /**
    * Tests deleting a shortcut set.
    */
   function testShortcutSetDelete() {
-    $new_set = $this->generateShortcutSet($this->randomName(10));
+    $new_set = $this->generateShortcutSet($this->randomName());
 
-    $this->drupalPost('admin/config/user-interface/shortcut/' . $new_set->set_name . '/delete', array(), t('Delete'));
-    $sets = shortcut_sets();
-    $this->assertFalse(isset($sets[$new_set->set_name]), 'Successfully deleted a shortcut set.');
+    $this->drupalPost('admin/config/user-interface/shortcut/manage/' . $new_set->id() . '/delete', array(), t('Delete'));
+    $sets = entity_load_multiple('shortcut');
+    $this->assertFalse(isset($sets[$new_set->id()]), 'Successfully deleted a shortcut set.');
   }
 
   /**
    * Tests deleting the default shortcut set.
    */
   function testShortcutSetDeleteDefault() {
-    $this->drupalGet('admin/config/user-interface/shortcut/' . SHORTCUT_DEFAULT_SET_NAME . '/delete');
+    $this->drupalGet('admin/config/user-interface/shortcut/manage/default/delete');
     $this->assertResponse(403);
   }
 
@@ -158,11 +159,11 @@ function testShortcutSetDeleteDefault() {
    * Tests creating a new shortcut set with a defined set name.
    */
   function testShortcutSetCreateWithSetName() {
-    $random_name = $this->randomName(10);
-    $new_set = $this->generateShortcutSet($random_name, TRUE, $random_name);
-    $sets = shortcut_sets();
+    $random_name = $this->randomName();
+    $new_set = $this->generateShortcutSet($random_name, $random_name, TRUE);
+    $sets = entity_load_multiple('shortcut');
     $this->assertTrue(isset($sets[$random_name]), 'Successfully created a shortcut set with a defined set name.');
     $this->drupalGet('user/' . $this->admin_user->uid . '/shortcuts');
-    $this->assertText($new_set->title, 'Generated shortcut set was listed as a choice on the user account page.');
+    $this->assertText($new_set->label(), 'Generated shortcut set was listed as a choice on the user account page.');
   }
 }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutTestBase.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutTestBase.php
index 8c94435..29cf2c1 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutTestBase.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutTestBase.php
@@ -8,7 +8,6 @@
 namespace Drupal\shortcut\Tests;
 
 use Drupal\simpletest\WebTestBase;
-use stdClass;
 
 /**
  * Defines base class for shortcut test cases.
@@ -51,7 +50,7 @@ function setUp() {
       $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
 
       // Populate the default shortcut set.
-      $shortcut_set = shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME);
+      $shortcut_set = shortcut_set_load('default');
       $shortcut_set->links[] = array(
         'link_path' => 'node/add',
         'link_title' => st('Add content'),
@@ -62,7 +61,7 @@ function setUp() {
         'link_title' => st('Find content'),
         'weight' => -19,
       );
-      shortcut_set_save($shortcut_set);
+      $shortcut_set->save();
     }
 
     // Create users.
@@ -74,29 +73,23 @@ function setUp() {
 
     // Log in as admin and grab the default shortcut set.
     $this->drupalLogin($this->admin_user);
-    $this->set = shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME);
+    $this->set = shortcut_set_load('default');
     shortcut_set_assign_user($this->set, $this->admin_user);
   }
 
   /**
    * Creates a generic shortcut set.
    */
-  function generateShortcutSet($title = '', $default_links = TRUE, $set_name = '') {
-    $set = new stdClass();
-    $set->title = empty($title) ? $this->randomName(10) : $title;
-
-    // Set name is generated automatically if not set.
-    if (!empty($set_name)) {
-      $set->set_name = $set_name;
-    }
-
-    if ($default_links) {
-      $set->links = array();
-      $set->links[] = $this->generateShortcutLink('node/add');
-      $set->links[] = $this->generateShortcutLink('admin/content');
-    }
-    shortcut_set_save($set);
-
+  function generateShortcutSet($label = '', $id = NULL, $default_links = TRUE) {
+    $set = entity_create('shortcut', array(
+      'id' => isset($id) ? $id : strtolower($this->randomName()),
+      'label' => empty($label) ? $this->randomString() : $label,
+      'links' => (!$default_links) ? array() : array(
+        $this->generateShortcutLink('node/add'),
+        $this->generateShortcutLink('admin/content'),
+      ),
+    ));
+    $set->save();
     return $set;
   }
 
@@ -106,7 +99,7 @@ function generateShortcutSet($title = '', $default_links = TRUE, $set_name = '')
   function generateShortcutLink($path, $title = '') {
     $link = array(
       'link_path' => $path,
-      'link_title' => !empty($title) ? $title : $this->randomName(10),
+      'link_title' => !empty($title) ? $title : $this->randomName(),
     );
 
     return $link;
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index e805acf..cb06a47 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -32,12 +32,12 @@ function shortcut_set_switch($form, &$form_state, $account = NULL) {
   }
 
   // Prepare the list of shortcut sets.
-  $sets = shortcut_sets();
+  $sets = entity_load_multiple('shortcut');
   $current_set = shortcut_current_displayed_set($account);
 
   $options = array();
   foreach ($sets as $name => $set) {
-    $options[$name] = check_plain($set->title);
+    $options[$name] = check_plain($set->label());
   }
 
   // Only administrators can add shortcut sets.
@@ -56,20 +56,37 @@ function shortcut_set_switch($form, &$form_state, $account = NULL) {
       '#type' => 'radios',
       '#title' => $user->uid == $account->uid ? t('Choose a set of shortcuts to use') : t('Choose a set of shortcuts for this user'),
       '#options' => $options,
-      '#default_value' => $current_set->set_name,
+      '#default_value' => $current_set->id(),
     );
 
-    $form['new'] = array(
+    $form['label'] = array(
       '#type' => 'textfield',
-      '#title' => t('Name'),
+      '#title' => t('Label'),
       '#title_display' => 'invisible',
       '#description' => t('The new set is created by copying items from your default shortcut set.'),
       '#access' => $add_access,
     );
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#machine_name' => array(
+        'exists' => 'shortcut_set_load',
+        'source' => array('label'),
+        'replace_pattern' => '[^a-z0-9-]+',
+        'replace' => '-',
+      ),
+      // This id could be used for menu name.
+      '#maxlength' => 23,
+      '#states' => array(
+        'required' => array(
+          ':input[name="set"]' => array('value' => 'new'),
+        ),
+      ),
+      '#required' => FALSE,
+    );
 
     if ($user->uid != $account->uid) {
       $default_set = shortcut_default_set($account);
-      $form['new']['#description'] = t('The new set is created by copying items from the %default set.', array('%default' => $default_set->title));
+      $form['new']['#description'] = t('The new set is created by copying items from the %default set.', array('%default' => $default_set->label()));
     }
 
     $form['#attached'] = array(
@@ -85,7 +102,7 @@ function shortcut_set_switch($form, &$form_state, $account = NULL) {
   else {
     // There is only 1 option, so output a message in the $form array.
     $form['info'] = array(
-      '#markup' => '<p>' . t('You are currently using the %set-name shortcut set.', array('%set-name' => $current_set->title)) . '</p>',
+      '#markup' => '<p>' . t('You are currently using the %set-name shortcut set.', array('%set-name' => $current_set->label())) . '</p>',
     );
   }
 
@@ -98,12 +115,12 @@ function shortcut_set_switch($form, &$form_state, $account = NULL) {
 function shortcut_set_switch_validate($form, &$form_state) {
   if ($form_state['values']['set'] == 'new') {
     // Check to prevent creating a shortcut set with an empty title.
-    if (trim($form_state['values']['new']) == '') {
-      form_set_error('new', t('The new set name is required.'));
+    if (trim($form_state['values']['label']) == '') {
+      form_set_error('new', t('The new set label is required.'));
     }
     // Check to prevent a duplicate title.
-    if (shortcut_set_title_exists($form_state['values']['new'])) {
-      form_set_error('new', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['new'])));
+    if (shortcut_set_title_exists($form_state['values']['label'])) {
+      form_set_error('label', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['label'])));
     }
   }
 }
@@ -118,14 +135,15 @@ function shortcut_set_switch_submit($form, &$form_state) {
   if ($form_state['values']['set'] == 'new') {
     // Save a new shortcut set with links copied from the user's default set.
     $default_set = shortcut_default_set($account);
-    $set = (object) array(
-      'title' => $form_state['values']['new'],
+    $set = entity_create('shortcut', array(
+      'id' => $form_state['values']['id'],
+      'label' => $form_state['values']['label'],
       'links' => menu_links_clone($default_set->links),
-    );
-    shortcut_set_save($set);
+    ));
+    $set->save();
     $replacements = array(
       '%user' => $account->name,
-      '%set_name' => $set->title,
+      '%set_name' => $set->label(),
       '@switch-url' => url(current_path()),
     );
     if ($account->uid == $user->uid) {
@@ -136,14 +154,14 @@ function shortcut_set_switch_submit($form, &$form_state) {
     else {
       drupal_set_message(t('%user is now using a new shortcut set called %set_name. You can edit it from this page.', $replacements));
     }
-    $form_state['redirect'] = 'admin/config/user-interface/shortcut/' . $set->set_name;
+    $form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set->id();
   }
   else {
     // Switch to a different shortcut set.
     $set = shortcut_set_load($form_state['values']['set']);
     $replacements = array(
       '%user' => $account->name,
-      '%set_name' => $set->title,
+      '%set_name' => $set->label(),
     );
     drupal_set_message($account->uid == $user->uid ? t('You are now using the %set_name shortcut set.', $replacements) : t('%user is now using the %set_name shortcut set.', $replacements));
   }
@@ -156,96 +174,15 @@ function shortcut_set_switch_submit($form, &$form_state) {
  * Menu page callback: builds the page for administering shortcut sets.
  */
 function shortcut_set_admin() {
-  $shortcut_sets = shortcut_sets();
-  $header = array(t('Name'), t('Operations'));
-
-  $rows = array();
-  foreach ($shortcut_sets as $set) {
-    $row = array(
-      check_plain($set->title),
-    );
-    $links['list'] = array(
-      'title' => t('list links'),
-      'href' => "admin/config/user-interface/shortcut/$set->set_name",
-    );
-    $links['edit'] = array(
-      'title' => t('list links'),
-      'href' => "admin/config/user-interface/shortcut/$set->set_name/edit",
-    );
-    if (shortcut_set_delete_access($set)) {
-      $links['delete'] = array(
-        'title' => t('delete set'),
-        'href' => "admin/config/user-interface/shortcut/$set->set_name/delete",
-      );
-    }
-    $row[] = array(
-      'data' => array(
-        '#type' => 'operations',
-        '#links' => $links,
-      ),
-    );
-
-    $rows[] = $row;
-  }
-
-  return theme('table', array('header' => $header, 'rows' => $rows));
-}
-
-/**
- * Form callback: builds the form for adding a shortcut set.
- *
- * @param $form
- *   An associative array containing the structure of the form.
- * @param $form_state
- *   An associative array containing the current state of the form.
- *
- * @return
- *   An array representing the form definition.
- *
- * @ingroup forms
- * @see shortcut_set_add_form_validate()
- * @see shortcut_set_add_form_submit()
- */
-function shortcut_set_add_form($form, &$form_state) {
-  $form['new'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Set name'),
-    '#description' => t('The new set is created by copying items from your default shortcut set.'),
-    '#required' => TRUE,
-  );
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Create new set'),
-  );
-
-  return $form;
+  return entity_list_controller('shortcut')->render();
 }
 
 /**
- * Validation handler for shortcut_set_add_form().
+ * Page callback: provides the shortcut set creation form.
  */
-function shortcut_set_add_form_validate($form, &$form_state) {
-  // Check to prevent a duplicate title.
-  if (shortcut_set_title_exists($form_state['values']['new'])) {
-    form_set_error('new', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['new'])));
-  }
-}
-
-/**
- * Submit handler for shortcut_set_add_form().
- */
-function shortcut_set_add_form_submit($form, &$form_state) {
-  // Save a new shortcut set with links copied from the user's default set.
-  $default_set = shortcut_default_set();
-  $set = (object) array(
-    'title' => $form_state['values']['new'],
-    'links' => menu_links_clone($default_set->links),
-  );
-  shortcut_set_save($set);
-  drupal_set_message(t('The %set_name shortcut set has been created. You can edit it from this page.', array('%set_name' => $set->title)));
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/' . $set->set_name;
+function shortcut_set_add() {
+  $entity = entity_create('shortcut', array());
+  return entity_get_form($entity);
 }
 
 /**
@@ -255,7 +192,7 @@ function shortcut_set_add_form_submit($form, &$form_state) {
  *   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
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   An object representing the shortcut set which is being edited.
  *
  * @return
@@ -265,7 +202,7 @@ function shortcut_set_add_form_submit($form, &$form_state) {
  * @see shortcut_set_customize_submit()
  */
 function shortcut_set_customize($form, &$form_state, $shortcut_set) {
-  $form['#shortcut_set_name'] = $shortcut_set->set_name;
+  $form['#shortcut_set_name'] = $shortcut_set->id();
   $form['shortcuts'] = array(
     '#tree' => TRUE,
     '#weight' => -20,
@@ -365,7 +302,7 @@ function theme_shortcut_set_customize($variables) {
  *   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
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   An object representing the shortcut set to which the link will be added.
  *
  * @return
@@ -486,7 +423,8 @@ function shortcut_link_edit_submit($form, &$form_state) {
   $shortcut_link = array_merge($form_state['values']['original_shortcut_link'], $form_state['values']['shortcut_link']);
 
   menu_link_save($shortcut_link);
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/' . $shortcut_link['menu_name'];
+  $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'])));
 }
 
@@ -497,10 +435,10 @@ 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->set_name;
+  $shortcut_link['menu_name'] = $shortcut_set->id();
   shortcut_admin_add_link($shortcut_link, $shortcut_set);
-  shortcut_set_save($shortcut_set);
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/' . $shortcut_link['menu_name'];
+  $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'])));
 }
 
@@ -509,7 +447,7 @@ function shortcut_link_add_submit($form, &$form_state) {
  *
  * @param $link
  *   An array representing a shortcut link.
- * @param $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\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
@@ -528,76 +466,13 @@ function shortcut_admin_add_link($shortcut_link, &$shortcut_set) {
 }
 
 /**
- * Form callback: builds the form for editing the shortcut set name.
- *
- * @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 object $shortcut_set
- *   An object representing the shortcut set, as returned from
- *   shortcut_set_load().
- *
- * @return
- *   An array representing the form definition.
- *
- * @ingroup forms
- * @see shortcut_set_edit_form_validate()
- * @see shortcut_set_edit_form_submit()
- */
-function shortcut_set_edit_form($form, &$form_state, $shortcut_set) {
-  $form['shortcut_set'] = array(
-    '#type' => 'value',
-    '#value' => $shortcut_set,
-  );
-  $form['title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Set name'),
-    '#default_value' => $shortcut_set->title,
-    '#maxlength' => 255,
-    '#required' => TRUE,
-    '#weight' => -5,
-  );
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#weight' => 5,
-  );
-
-  return $form;
-}
-
-/**
- * Validation handler for shortcut_set_edit_form().
- */
-function shortcut_set_edit_form_validate($form, &$form_state) {
-  // Check to prevent a duplicate title, if the title was edited from its
-  // original value.
-  if ($form_state['values']['title'] != $form_state['values']['shortcut_set']->title && shortcut_set_title_exists($form_state['values']['title'])) {
-    form_set_error('title', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['title'])));
-  }
-}
-
-/**
- * Submit handler for shortcut_set_edit_form().
- */
-function shortcut_set_edit_form_submit($form, &$form_state) {
-  $shortcut_set = $form_state['values']['shortcut_set'];
-  $shortcut_set->title = $form_state['values']['title'];
-  shortcut_set_save($shortcut_set);
-  drupal_set_message(t('Updated set name to %set-name.', array('%set-name' => $shortcut_set->title)));
-  $form_state['redirect'] = "admin/config/user-interface/shortcut/$shortcut_set->set_name";
-}
-
-/**
  * Form callback: builds the confirmation form for deleting a shortcut set.
  *
  * @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 object $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   An object representing the shortcut set, as returned from
  *   shortcut_set_load().
  *
@@ -610,12 +485,12 @@ function shortcut_set_edit_form_submit($form, &$form_state) {
 function shortcut_set_delete_form($form, &$form_state, $shortcut_set) {
   $form['shortcut_set'] = array(
     '#type' => 'value',
-    '#value' => $shortcut_set->set_name,
+    '#value' => $shortcut_set->id(),
   );
 
   // Find out how many users are directly assigned to this shortcut set, and
   // make a message.
-  $number = db_query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $shortcut_set->set_name))->fetchField();
+  $number = db_query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $shortcut_set->id()))->fetchField();
   $info = '';
   if ($number) {
     $info .= '<p>' . format_plural($number,
@@ -635,8 +510,8 @@ function shortcut_set_delete_form($form, &$form_state, $shortcut_set) {
 
   return confirm_form(
     $form,
-    t('Are you sure you want to delete the shortcut set %title?', array('%title' => $shortcut_set->title)),
-    'admin/config/user-interface/shortcut/' . $shortcut_set->set_name,
+    t('Are you sure you want to delete the shortcut set %title?', array('%title' => $shortcut_set->label())),
+    'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id(),
     t('This action cannot be undone.'),
     t('Delete'),
     t('Cancel')
@@ -648,9 +523,10 @@ function shortcut_set_delete_form($form, &$form_state, $shortcut_set) {
  */
 function shortcut_set_delete_form_submit($form, &$form_state) {
   $shortcut_set = shortcut_set_load($form_state['values']['shortcut_set']);
-  shortcut_set_delete($shortcut_set);
+  $label = $shortcut_set->label();
+  $shortcut_set->delete();
   $form_state['redirect'] = 'admin/config/user-interface/shortcut';
-  drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $shortcut_set->title)));
+  drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $label)));
 }
 
 /**
@@ -678,7 +554,7 @@ function shortcut_link_delete($form, &$form_state, $shortcut_link) {
   return confirm_form(
     $form,
     t('Are you sure you want to delete the shortcut %title?', array('%title' => $shortcut_link['link_title'])),
-    'admin/config/user-interface/shortcut/' . $shortcut_link['menu_name'],
+    'admin/config/user-interface/shortcut/manage/' . $shortcut_link['menu_name'],
     t('This action cannot be undone.'),
     t('Delete'),
     t('Cancel')
@@ -691,7 +567,8 @@ function shortcut_link_delete($form, &$form_state, $shortcut_link) {
 function shortcut_link_delete_submit($form, &$form_state) {
   $shortcut_link = $form_state['values']['shortcut_link'];
   menu_link_delete($shortcut_link['mlid']);
-  $form_state['redirect'] = 'admin/config/user-interface/shortcut/' . $shortcut_link['menu_name'];
+  $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 %title has been deleted.', array('%title' => $shortcut_link['link_title'])));
 }
 
@@ -700,7 +577,7 @@ function shortcut_link_delete_submit($form, &$form_state) {
  *
  * After completion, redirects the user back to where they came from.
  *
- * @param $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   Returned from shortcut_set_load().
  */
 function shortcut_link_add_inline($shortcut_set) {
@@ -712,7 +589,7 @@ function shortcut_link_add_inline($shortcut_set) {
       'link_path' => $_GET['link'],
     );
     shortcut_admin_add_link($link, $shortcut_set);
-    if (shortcut_set_save($shortcut_set)) {
+    if ($shortcut_set->save()) {
       drupal_set_message(t('Added a shortcut for %title.', array('%title' => $link['link_title'])));
     }
     else {
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index c4023d7..737194b 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -6,59 +6,20 @@
  */
 
 /**
- * Implements hook_install().
- */
-function shortcut_install() {
-  $t = get_t();
-  // Create an initial default shortcut set.
-  $shortcut_set = new stdClass();
-  $shortcut_set->title = $t('Default');
-  $shortcut_set->links = array();
-  shortcut_set_save($shortcut_set);
-}
-
-/**
  * Implements hook_uninstall().
  */
 function shortcut_uninstall() {
-  drupal_load('module', 'shortcut');
   // Delete the menu links associated with each shortcut set.
-  foreach (shortcut_sets() as $shortcut_set) {
-    menu_delete_links($shortcut_set->set_name);
-  }
+  // @todo find a way to clean-up associated menu links.
+  /*foreach (entity_load_multiple('shortcut') as $shortcut_set) {
+    menu_delete_links('shortcut-' . $shortcut_set->id());
+  }*/
 }
 
 /**
  * Implements hook_schema().
  */
 function shortcut_schema() {
-  $schema['shortcut_set'] = array(
-    'description' => 'Stores information about sets of shortcuts links.',
-    'fields' => array(
-      'set_name' => array(
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => "Primary Key: The {menu_links}.menu_name under which the set's links are stored.",
-      ),
-      'title' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The title of the set.',
-      ),
-    ),
-    'primary key' => array('set_name'),
-    'foreign keys' => array(
-      'menu_name' => array(
-        'table' => 'menu_links',
-        'columns' => array('set_name' => 'menu_name'),
-      ),
-    ),
-  );
-
   $schema['shortcut_set_users'] = array(
     'description' => 'Maps users to shortcut sets.',
     'fields' => array(
@@ -95,3 +56,45 @@ function shortcut_schema() {
 
   return $schema;
 }
+
+/**
+ * @defgroup updates-7.x-to-8.x Updates from 7.x to 8.x
+ * @{
+ * Update functions from 7.x to 8.x.
+ */
+
+/**
+ * Migrate shortcuts into configuration.
+ */
+function shortcut_update_8000() {
+  $result = db_query('SELECT * from {shortcut_set}');
+  foreach ($result as $set) {
+    // Save a config object.
+    if ($set->set_name == 'shortcut-set-1') {
+      // Change default shortcut id.
+      $set->set_name = 'default';
+      // Update menu links.
+      $links = menu_load_links('shortcut-set-1');
+      foreach ($links as $link) {
+        $link['menu_name'] = 'shortcut-default';
+        menu_link_save($link);
+      }
+    }
+    config('shortcut.set.' . $set->set_name)
+      ->set('id', $set->set_name)
+      ->set('label', $set->title)
+      ->save();
+  }
+}
+
+/**
+ * Drop the {shortcut_set} table.
+ */
+function shortcut_update_8001() {
+  db_drop_table('shortcut_set');
+}
+
+/**
+ * @} End of "defgroup updates-7.x-to-8.x".
+ * The next series of updates should start at 9000.
+ */
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 9bbb12a..b809ab0 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -5,13 +5,7 @@
  * Allows users to manage customizable lists of shortcut links.
  */
 
-/**
- * The name of the default shortcut set.
- *
- * This set will be displayed to any user that does not have another set
- * assigned, unless overridden by a hook_shortcut_default_set() implementation.
- */
-const SHORTCUT_DEFAULT_SET_NAME = 'shortcut-set-1';
+use Drupal\shortcut\Plugin\Core\Entity\Shortcut;
 
 /**
  * Implements hook_help().
@@ -76,59 +70,58 @@ function shortcut_menu() {
   );
   $items['admin/config/user-interface/shortcut/add-set'] = array(
     'title' => 'Add shortcut set',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_set_add_form'),
+    'page callback' => 'shortcut_set_add',
     'access arguments' => array('administer shortcuts'),
     'type' => MENU_LOCAL_ACTION,
     'file' => 'shortcut.admin.inc',
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set'] = array(
+  $items['admin/config/user-interface/shortcut/manage/%shortcut_set'] = array(
     'title' => 'Edit shortcuts',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_set_customize', 4),
-    'title callback' => 'shortcut_set_title',
-    'title arguments' => array(4),
+    'page arguments' => array('shortcut_set_customize', 5),
+    'title callback' => 'entity_page_label',
+    'title arguments' => array(5),
     'access callback' => 'shortcut_set_edit_access',
-    'access arguments' => array(4),
+    'access arguments' => array(5),
     'file' => 'shortcut.admin.inc',
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set/links'] = array(
+  $items['admin/config/user-interface/shortcut/manage/%shortcut_set/links'] = array(
     'title' => 'List links',
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set/edit'] = array(
+  $items['admin/config/user-interface/shortcut/manage/%shortcut_set/edit'] = array(
     'title' => 'Edit set name',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_set_edit_form', 4),
+    'page callback' => 'entity_get_form',
+    'page arguments' => array(5),
     'access callback' => 'shortcut_set_edit_access',
-    'access arguments' => array(4),
+    'access arguments' => array(5),
     'type' => MENU_LOCAL_TASK,
     'file' => 'shortcut.admin.inc',
     'weight' => 10,
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set/delete'] = array(
+  $items['admin/config/user-interface/shortcut/manage/%shortcut_set/delete'] = array(
     'title' => 'Delete shortcut set',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_set_delete_form', 4),
+    'page arguments' => array('shortcut_set_delete_form', 5),
     'access callback' => 'shortcut_set_delete_access',
-    'access arguments' => array(4),
+    'access arguments' => array(5),
     'file' => 'shortcut.admin.inc',
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set/add-link'] = array(
+  $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', 4),
+    'page arguments' => array('shortcut_link_add', 5),
     'access callback' => 'shortcut_set_edit_access',
-    'access arguments' => array(4),
+    'access arguments' => array(5),
     'type' => MENU_LOCAL_ACTION,
     'file' => 'shortcut.admin.inc',
   );
-  $items['admin/config/user-interface/shortcut/%shortcut_set/add-link-inline'] = array(
+  $items['admin/config/user-interface/shortcut/manage/%shortcut_set/add-link-inline'] = array(
     'title' => 'Add shortcut',
     'page callback' => 'shortcut_link_add_inline',
-    'page arguments' => array(4),
+    'page arguments' => array(5),
     'access callback' => 'shortcut_set_edit_access',
-    'access arguments' => array(4),
+    'access arguments' => array(5),
     'type' => MENU_CALLBACK,
     'file' => 'shortcut.admin.inc',
   );
@@ -209,7 +202,7 @@ function shortcut_block_view($delta = '') {
 /**
  * Access callback for editing a shortcut set.
  *
- * @param object $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   (optional) The shortcut set to be edited. If not set, the current user's
  *   shortcut set will be used.
  *
@@ -232,7 +225,7 @@ function shortcut_set_edit_access($shortcut_set = NULL) {
 /**
  * Access callback for deleting a shortcut set.
  *
- * @param $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   The shortcut set to be deleted.
  *
  * @return
@@ -246,7 +239,7 @@ function shortcut_set_delete_access($shortcut_set) {
   }
 
   // Never let the default shortcut set be deleted.
-  if ($shortcut_set->set_name == SHORTCUT_DEFAULT_SET_NAME) {
+  if ($shortcut_set->id() == 'default') {
     return FALSE;
   }
 
@@ -293,125 +286,104 @@ function shortcut_set_switch_access($account = NULL) {
 function shortcut_link_access($menu_link) {
   // The link must belong to a shortcut set that the current user has access
   // to edit.
-  if ($shortcut_set = shortcut_set_load($menu_link['menu_name'])) {
+  $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;
 }
 
 /**
- * Loads the data for a shortcut set.
- *
- * @param $set_name
- *   The name of the shortcut set to load.
- *
- * @return object
- *   If the shortcut set exists, an object containing the following properties:
- *   - 'set_name': The internal name of the shortcut set.
- *   - 'title': The title of the shortcut set.
- *   - 'links': An array of links associated with this shortcut set.
- *   If the shortcut set does not exist, the function returns FALSE.
+ * Implements hook_config_import_create().
  */
-function shortcut_set_load($set_name) {
-  $set = db_select('shortcut_set', 'ss')
-  ->fields('ss')
-  ->condition('set_name', $set_name)
-  ->execute()
-  ->fetchObject();
-  if (!$set) {
+function shortcut_config_import_create($name, $new_config, $old_config) {
+  if (strpos($name, 'shortcut.set.') !== 0) {
     return FALSE;
   }
-  $set->links = menu_load_links($set_name);
-  return $set;
+
+  $entity = entity_create('shortcut', $new_config->get());
+  $entity->save();
+  return TRUE;
 }
 
 /**
- * Saves a shortcut set.
- *
- * @param $shortcut_set
- *   An object containing the following properties:
- *   - 'title': The title of the shortcut set.
- *   - 'set_name': (optional) The internal name of the shortcut set. If
- *     omitted, a new shortcut set will be created, and the 'set_name' property
- *     will be added to the passed-in object.
- *   - 'links': (optional) An array of menu links to save for the shortcut set.
- *     Each link is an array containing at least the following keys (which will
- *     be expanded to fill in other default values after the shortcut set is
- *     saved):
- *     - 'link_path': The Drupal path or external path that the link points to.
- *     - 'link_title': The title of the link.
- *     Any other keys accepted by menu_link_save() may also be provided.
- *
- * @return
- *   A constant which is either SAVED_NEW or SAVED_UPDATED depending on whether
- *   a new set was created or an existing one was updated.
- *
- * @see menu_link_save()
+ * Implements hook_config_import_change().
  */
-function shortcut_set_save(&$shortcut_set) {
-  // First save the shortcut set itself.
-  if (isset($shortcut_set->set_name)) {
-    $return = db_merge('shortcut_set')
-      ->key(array('set_name' => $shortcut_set->set_name))
-      ->fields(array('title' => $shortcut_set->title))
-      ->execute();
+function shortcut_config_import_change($name, $new_config, $old_config) {
+  if (strpos($name, 'shortcut.set.') !== 0) {
+    return FALSE;
   }
-  else {
-    $shortcut_set->set_name = shortcut_set_get_unique_name();
-    $return = drupal_write_record('shortcut_set', $shortcut_set);
+
+  list(, , $id) = explode('.', $name);
+  $entity = entity_load('shortcut', $id);
+
+  $entity->original = clone $entity;
+  foreach ($old_config->get() as $property => $value) {
+    $entity->original->$property = $value;
   }
-  // If links were provided for the set, save them.
-  if (isset($shortcut_set->links)) {
-    foreach ($shortcut_set->links as &$link) {
-      // Do not specifically associate these links with the shortcut module,
-      // since other modules may make them editable via the menu system.
-      // However, we do need to specify the correct menu name.
-      $link['menu_name'] = $shortcut_set->set_name;
-      $link['plid'] = 0;
-      menu_link_save($link);
-    }
-    // Make sure that we have a return value, since if the links were updated
-    // but the shortcut set was not, the call to drupal_write_record() above
-    // would not return an indication that anything had changed.
-    if (empty($return)) {
-      $return = SAVED_UPDATED;
-    }
+
+  foreach ($new_config->get() as $property => $value) {
+    $entity->$property = $value;
   }
-  return $return;
+
+  $entity->save();
+  return TRUE;
 }
 
 /**
- * Deletes a shortcut set.
- *
- * Note that the default set cannot be deleted.
- *
- * @param $shortcut_set
- *   An object representing the shortcut set to delete.
- *
- * @return
- *   TRUE if the set was deleted, FALSE otherwise.
+ * Implements hook_config_import_delete().
  */
-function shortcut_set_delete($shortcut_set) {
-  // Don't allow deletion of the system default shortcut set.
-  if ($shortcut_set->set_name == SHORTCUT_DEFAULT_SET_NAME) {
+function shortcut_config_import_delete($name, $new_config, $old_config) {
+  if (strpos($name, 'shortcut.set.') !== 0) {
     return FALSE;
   }
 
-  // First, delete any user assignments for this set, so that each of these
-  // users will go back to using whatever default set applies.
-  db_delete('shortcut_set_users')
-    ->condition('set_name', $shortcut_set->set_name)
-    ->execute();
+  list(, , $id) = explode('.', $name);
+  entity_delete_multiple('shortcut', array($id));
+  return TRUE;
+}
 
-  // Next, delete the menu links for this set.
-  menu_delete_links($shortcut_set->set_name);
+/**
+ * Loads the data for a shortcut set.
+ *
+ * @param $id
+ *   The machine-name of the shortcut set to load.
+ *
+ * @return object
+ *   If the shortcut set exists, an object containing the following properties:
+ *   - 'id': The internal name of the shortcut set.
+ *   - 'label': The title of the shortcut set.
+ *   - 'links': An array of links associated with this shortcut set.
+ *   If the shortcut set does not exist, the function returns FALSE.
+ */
+function shortcut_set_load($id) {
+  return entity_load('shortcut', $id);
+}
 
-  // Finally, delete the set itself.
-  $deleted = db_delete('shortcut_set')
-    ->condition('set_name', $shortcut_set->set_name)
-    ->execute();
+/**
+ * Implements hook_shortcut_load().
+ *
+ * Loads menu links attached to each of shortcuts.
+ */
+function shortcut_shortcut_load($entities) {
+  foreach ($entities as $id => $entity) {
+    $entity->set('links', menu_load_links('shortcut-' . $id));
+  }
+}
 
-  return (bool) $deleted;
+/**
+ * Entity URI callback.
+ *
+ * @param $shortcut Drupal\shortcut\Shortcut
+ *   A shortcut set entity.
+ *
+ * @return array
+ *   An array with 'path' as the key and the path to the set as the value.
+ */
+function shortcut_uri(Shortcut $shortcut) {
+  return array(
+    'path' => 'admin/config/user-interface/shortcut/manage/' . $shortcut->id(),
+  );
 }
 
 /**
@@ -436,7 +408,7 @@ function shortcut_set_reset_link_weights(&$shortcut_set) {
 /**
  * Assigns a user to a particular shortcut set.
  *
- * @param $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   An object representing the shortcut set.
  * @param $account
  *   A user account that will be assigned to use the set.
@@ -444,7 +416,7 @@ function shortcut_set_reset_link_weights(&$shortcut_set) {
 function shortcut_set_assign_user($shortcut_set, $account) {
   db_merge('shortcut_set_users')
     ->key(array('uid' => $account->uid))
-    ->fields(array('set_name' => $shortcut_set->set_name))
+    ->fields(array('set_name' => $shortcut_set->id()))
     ->execute();
   drupal_static_reset('shortcut_current_displayed_set');
 }
@@ -493,10 +465,9 @@ function shortcut_current_displayed_set($account = NULL) {
   }
   // If none was found, try to find a shortcut set that is explicitly assigned
   // to this user.
-  $query = db_select('shortcut_set', 's');
-  $query->addField('s', 'set_name');
-  $query->join('shortcut_set_users', 'u', 's.set_name = u.set_name');
-  $query->condition('u.uid', $account->uid);
+  $query = db_select('shortcut_set_users', 'ssu');
+  $query->fields('ssu', array('set_name'));
+  $query->condition('ssu.uid', $account->uid);
   $shortcut_set_name = $query->execute()->fetchField();
   if ($shortcut_set_name) {
     $shortcut_set = shortcut_set_load($shortcut_set_name);
@@ -532,7 +503,7 @@ function shortcut_default_set($account = NULL) {
   // precedence. If no module returns a valid set, fall back on the site-wide
   // default, which is the lowest-numbered shortcut set.
   $suggestions = array_reverse(module_invoke_all('shortcut_default_set', $account));
-  $suggestions[] = SHORTCUT_DEFAULT_SET_NAME;
+  $suggestions[] = 'default';
   foreach ($suggestions as $name) {
     if ($shortcut_set = shortcut_set_load($name)) {
       break;
@@ -543,54 +514,6 @@ function shortcut_default_set($account = NULL) {
 }
 
 /**
- * Returns a unique, machine-readable shortcut set name.
- */
-function shortcut_set_get_unique_name() {
-  // Shortcut sets are numbered sequentially, so we keep trying until we find
-  // one that is available. For better performance, we start with a number
-  // equal to one more than the current number of shortcut sets, so that if
-  // no shortcut sets have been deleted from the database, this will
-  // automatically give us the correct one.
-  $number = db_query("SELECT COUNT(*) FROM {shortcut_set}")->fetchField() + 1;
-  do {
-    $name = shortcut_set_name($number);
-    $number++;
-  } while ($shortcut_set = shortcut_set_load($name));
-  return $name;
-}
-
-/**
- * Returns the name of a shortcut set, based on a provided number.
- *
- * All shortcut sets have names like "shortcut-set-N" so that they can be
- * matched with a properly-namespaced entry in the {menu_links} table.
- *
- * @param $number
- *   A number representing the shortcut set whose name should be retrieved.
- *
- * @return
- *   A string representing the expected shortcut name.
- */
-function shortcut_set_name($number) {
-  return "shortcut-set-$number";
-}
-
-/**
- * Returns an array of all shortcut sets, keyed by the set name.
- *
- * @return
- *   An array of shortcut sets. Note that only the basic shortcut set
- *   properties (name and title) are returned by this function, not the list
- *   of menu links that belong to the set.
- */
-function shortcut_sets() {
-  return db_select('shortcut_set', 'ss')
-  ->fields('ss')
-  ->execute()
-  ->fetchAllAssoc('set_name');
-}
-
-/**
  * Check to see if a shortcut set with the given title already exists.
  *
  * @param $title
@@ -600,7 +523,13 @@ function shortcut_sets() {
  *   TRUE if a shortcut set with that title exists; FALSE otherwise.
  */
 function shortcut_set_title_exists($title) {
-  return (bool) db_query_range('SELECT 1 FROM {shortcut_set} WHERE title = :title', 0, 1, array(':title' => $title))->fetchField();
+  $sets = entity_load_multiple('shortcut');
+  foreach ($sets as $id => $set) {
+    if ($set->label == $title) {
+      return TRUE;
+    }
+  }
+  return FALSE;
 }
 
 /**
@@ -608,6 +537,7 @@ function shortcut_set_title_exists($title) {
  *
  * @param $path
  *   The path to the link.
+ *
  * @return
  *   TRUE if the shortcut link is valid, FALSE otherwise. Valid links are ones
  *   that correspond to actual paths on the site.
@@ -627,7 +557,7 @@ function shortcut_valid_link($path) {
 /**
  * Returns an array of shortcut links, suitable for rendering.
  *
- * @param $shortcut_set
+ * @param $shortcut_set Drupal\shortcut\Shortcut
  *   (optional) An object representing the set whose links will be displayed.
  *   If not provided, the user's current set will be displayed.
  * @return
@@ -639,7 +569,7 @@ function shortcut_renderable_links($shortcut_set = NULL) {
   if (!isset($shortcut_set)) {
     $shortcut_set = shortcut_current_displayed_set();
   }
-  return menu_tree($shortcut_set->set_name);
+  return menu_tree('shortcut-' . $shortcut_set->id());
 }
 
 /**
@@ -684,12 +614,12 @@ function shortcut_preprocess_page(&$variables) {
 
     if ($link_mode == "add") {
       $query['token'] = drupal_get_token('shortcut-add-link');
-      $link_text = shortcut_set_switch_access() ? t('Add to %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->title)) : t('Add to shortcuts');
-      $link_path = 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name . '/add-link-inline';
+      $link_text = shortcut_set_switch_access() ? t('Add to %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->label())) : t('Add to shortcuts');
+      $link_path = 'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id() . '/add-link-inline';
     }
     else {
       $query['mlid'] = $mlid;
-      $link_text = shortcut_set_switch_access() ? t('Remove from %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->title)) : t('Remove from shortcuts');
+      $link_text = shortcut_set_switch_access() ? t('Remove from %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->label())) : t('Remove from shortcuts');
       $link_path = 'admin/config/user-interface/shortcut/link/' . $mlid . '/delete';
     }
 
@@ -742,7 +672,7 @@ function shortcut_toolbar_pre_render($toolbar) {
     $configure_link = array(
       '#type' => 'link',
       '#title' => t('Edit shortcuts'),
-      '#href' => 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name,
+      '#href' => 'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id(),
       '#options' => array('attributes' => array('id' => 'edit-shortcuts')),
     );
   }
@@ -757,19 +687,6 @@ function shortcut_toolbar_pre_render($toolbar) {
 }
 
 /**
- * Returns the title of a shortcut set.
- *
- * Title callback for the editing pages for shortcut sets.
- *
- * @param $shortcut_set
- *   An object representing the shortcut set, as returned by
- *   shortcut_set_load().
- */
-function shortcut_set_title($shortcut_set) {
-  return $shortcut_set->title;
-}
-
-/**
  * Implements hook_library_info().
  */
 function shortcut_library_info() {
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index b4dc761..54d8cb9 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -402,7 +402,7 @@ function standard_install() {
   menu_link_save($item);
 
   // Populate the default shortcut set.
-  $shortcut_set = shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME);
+  $shortcut_set = shortcut_set_load('default');
   $shortcut_set->links[] = array(
     'link_path' => 'node/add',
     'link_title' => st('Add content'),
@@ -413,7 +413,7 @@ function standard_install() {
     'link_title' => st('Find content'),
     'weight' => -19,
   );
-  shortcut_set_save($shortcut_set);
+  $shortcut_set->save();
 
   // Update the menu router information.
   menu_router_rebuild();
