diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/SetSwitch.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetSwitch.php
new file mode 100644
index 0000000..6d4c88f
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetSwitch.php
@@ -0,0 +1,225 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\shortcut\Form\SetSwitch.
+ */
+
+namespace Drupal\shortcut\Form;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Form\FormInterface;
+use Drupal\Component\Utility\String;
+use Drupal\user\UserInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Builds the shortcut set switch form.
+ */
+class SetSwitch implements ControllerInterface, FormInterface {
+
+  /**
+   * The account the shortcut set is for.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $account;
+
+  /**
+   * The request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * The shortcut storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $storageController;
+
+  /**
+   * Constructs a SetSwitch object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->storageController = $entity_manager->getStorageController('shortcut');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.entity')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'shortcut_set_switch';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state, UserInterface $account = NULL, Request $request = NULL) {
+    global $user;
+    $this->request = $request;
+    $this->account = $account;
+
+    // Prepare the list of shortcut sets.
+    $options = array_map(function ($set) {
+      return String::checkPlain($set->label());
+    }, $this->storageController->load());
+
+    $current_set = shortcut_current_displayed_set($this->account->getBCEntity());
+
+    // Only administrators can add shortcut sets.
+    $add_access = user_access('administer shortcuts');
+    if ($add_access) {
+      $options['new'] = t('New set');
+    }
+
+    $account_is_user = $this->account->id() == $user->uid;
+    if (count($options) > 1) {
+      $form['set'] = array(
+        '#type' => 'radios',
+        '#title' => $account_is_user ? t('Choose a set of shortcuts to use') : t('Choose a set of shortcuts for this user'),
+        '#options' => $options,
+        '#default_value' => $current_set->id(),
+      );
+
+      $form['label'] = array(
+        '#type' => 'textfield',
+        '#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' => array($this, 'exists'),
+          '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 (!$account_is_user) {
+        $default_set = shortcut_default_set($this->account->getBCEntity());
+        $form['new']['#description'] = t('The new set is created by copying items from the %default set.', array('%default' => $default_set->label()));
+      }
+
+      $form['#attached'] = array(
+        'library' => array(array('shortcut', 'drupal.shortcut.admin')),
+      );
+
+      $form['actions'] = array('#type' => 'actions');
+      $form['actions']['submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Change set'),
+      );
+    }
+    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->label())) . '</p>',
+      );
+    }
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    if ($form_state['values']['set'] == 'new') {
+      // Check to prevent creating a shortcut set with an empty title.
+      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']['label'])) {
+        form_set_error('label', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['label'])));
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    global $user;
+
+    $account_is_user = $this->account->id() == $user->uid;
+    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($this->account);
+      $set = $this->storageController->create(array(
+        'id' => $form_state['values']['id'],
+        'label' => $form_state['values']['label'],
+        'links' => $default_set->links,
+      ));
+      $set->save();
+      $replacements = array(
+        '%user' => $this->account->label(),
+        '%set_name' => $set->label(),
+        '@switch-url' => url($this->request->attributes->get('system_path')),
+      );
+      if ($account_is_user) {
+        // Only administrators can create new shortcut sets, so we know they have
+        // access to switch back.
+        drupal_set_message(t('You are now using the new %set_name shortcut set. You can edit it from this page or <a href="@switch-url">switch back to a different one.</a>', $replacements));
+      }
+      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/manage/' . $set->id();
+    }
+    else {
+      // Switch to a different shortcut set.
+      $sets = $this->storageController->load(array($form_state['values']['set']));
+      $set = reset($sets);
+      $replacements = array(
+        '%user' => $this->account->label(),
+        '%set_name' => $set->label(),
+      );
+      drupal_set_message($account_is_user ? t('You are now using the %set_name shortcut set.', $replacements) : t('%user is now using the %set_name shortcut set.', $replacements));
+    }
+
+    // Assign the shortcut set to the provided user account.
+    shortcut_set_assign_user($set, $this->account);
+  }
+
+  /**
+   * Determines if a shortcut set exists already.
+   *
+   * @param string $id
+   *   The set ID to check.
+   *
+   * @return bool
+   *   TRUE if the shortcut set exists, FALSE otherwise.
+   */
+  public function exists($id) {
+    $sets = $this->storageController->load(array($id));
+    return !empty($sets[$id]);
+  }
+
+}
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index e8ab3b5..5a94e4d 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -7,168 +7,6 @@
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
-/**
- * Form callback: builds the form for switching shortcut sets.
- *
- * @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 $account
- *   (optional) The user account whose shortcuts will be switched. Defaults to
- *   the current logged-in user.
- *
- * @return
- *   An array representing the form definition.
- *
- * @ingroup forms
- * @see shortcut_set_switch_validate()
- * @see shortcut_set_switch_submit()
- */
-function shortcut_set_switch($form, &$form_state, $account = NULL) {
-  global $user;
-  if (!isset($account)) {
-    $account = $user;
-  }
-
-  // Prepare the list of 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->label());
-  }
-
-  // Only administrators can add shortcut sets.
-  $add_access = user_access('administer shortcuts');
-  if ($add_access) {
-    $options['new'] = t('New set');
-  }
-
-  if (count($options) > 1) {
-    $form['account'] = array(
-      '#type' => 'value',
-      '#value' => $account,
-    );
-
-    $form['set'] = array(
-      '#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->id(),
-    );
-
-    $form['label'] = array(
-      '#type' => 'textfield',
-      '#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->label()));
-    }
-
-    $form['#attached'] = array(
-      'library' => array(array('shortcut', 'drupal.shortcut.admin')),
-    );
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Change set'),
-    );
-  }
-  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->label())) . '</p>',
-    );
-  }
-
-  return $form;
-}
-
-/**
- * Validation handler for shortcut_set_switch().
- */
-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']['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']['label'])) {
-      form_set_error('label', t('The shortcut set %name already exists. Choose another name.', array('%name' => $form_state['values']['label'])));
-    }
-  }
-}
-
-/**
- * Submit handler for shortcut_set_switch().
- */
-function shortcut_set_switch_submit($form, &$form_state) {
-  global $user;
-  $account = $form_state['values']['account'];
-
-  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 = entity_create('shortcut', array(
-      'id' => $form_state['values']['id'],
-      'label' => $form_state['values']['label'],
-      'links' => $default_set->links,
-    ));
-    $set->save();
-    $replacements = array(
-      '%user' => $account->name,
-      '%set_name' => $set->label(),
-      '@switch-url' => url(current_path()),
-    );
-    if ($account->uid == $user->uid) {
-      // Only administrators can create new shortcut sets, so we know they have
-      // access to switch back.
-      drupal_set_message(t('You are now using the new %set_name shortcut set. You can edit it from this page or <a href="@switch-url">switch back to a different one.</a>', $replacements));
-    }
-    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/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->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));
-  }
-
-  // Assign the shortcut set to the provided user account.
-  shortcut_set_assign_user($set, $account);
-}
 
 /**
  * Page callback: provides the shortcut set creation form.
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 8de14a0..1443e0a 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -152,12 +152,8 @@ function shortcut_menu() {
   );
   $items['user/%user/shortcuts'] = array(
     'title' => 'Shortcuts',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('shortcut_set_switch', 1),
-    'access callback' => 'shortcut_set_switch_access',
-    'access arguments' => array(1),
+    'route_name' => 'shortcut_set_switch',
     'type' => MENU_LOCAL_TASK,
-    'file' => 'shortcut.admin.inc',
   );
 
   return $items;
diff --git a/core/modules/shortcut/shortcut.routing.yml b/core/modules/shortcut/shortcut.routing.yml
index 761067f..b7fb77c 100644
--- a/core/modules/shortcut/shortcut.routing.yml
+++ b/core/modules/shortcut/shortcut.routing.yml
@@ -24,3 +24,13 @@ shortcut_set_edit:
     _entity_form: 'shortcut.edit'
   requirements:
     _entity_access: 'shortcut.edit'
+
+shortcut_set_switch:
+  pattern: '/user/{account}/shortcuts'
+  defaults:
+    _form: 'Drupal\shortcut\Form\SetSwitch'
+  options:
+    converters:
+      account: 'user'
+  requirements:
+    _access: 'TRUE'
