diff --git a/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php
index 0cb7c68..168ecdc 100644
--- a/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php
+++ b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php
@@ -2,38 +2,70 @@
 
 namespace Drupal\migrate\Plugin\migrate\process;
 
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Menu\MenuLinkManagerInterface;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Url;
+use Drupal\migrate\Plugin\MigratePluginManagerInterface;
 use Drupal\migrate\Plugin\MigrationInterface;
 use Drupal\migrate\MigrateExecutableInterface;
 use Drupal\migrate\MigrateSkipRowException;
-use Drupal\migrate\Plugin\MigrateProcessInterface;
-use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
 use Drupal\migrate\Row;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * This plugin figures out menu link parent plugin IDs.
+ * Determines the parent of a menu link.
+ *
+ * Menu link item belongs to a menu such as 'Navigation' or 'Administration'.
+ * Menu link item also has a parent item unless it is the root element of the
+ * menu.
+ *
+ * This process plugin determines the parent item of a menu link. If the parent
+ * item can't be determined by ID, we try to determine it by a combination of
+ * menu name and parent link path.
+ *
+ * The source is an array of three values:
+ * - parent_id: The numeric ID of the parent menu link, or 0 if the link is the
+ *   root element of the menu.
+ * - menu_name: The name of the menu the menu link item belongs to.
+ * - parent_link_path: The Drupal path or external URL this menu link points to.
+ *
+ * Example:
+ *
+ * @code
+ * process:
+ *   parent:
+ *     plugin: menu_link_parent
+ *     source:
+ *       - '20'
+ *       - 'admin'
+ *       - 'admin/structure'
+ * @endcode
+ * In this example we first try to look up a menu link item that had an ID '20'
+ * in the source. If a parent menu item can't be found with this ID, we try to
+ * determine the parent by a combination of 'admin' menu name and
+ * 'admin/structure' menu link path.
+ *
+ * @see https://www.drupal.org/docs/8/api/menu-api
+ * @see \Drupal\migrate\Plugin\MigrateProcessInterface
  *
  * @MigrateProcessPlugin(
  *   id = "menu_link_parent"
  * )
  */
-class MenuLinkParent extends ProcessPluginBase implements ContainerFactoryPluginInterface {
+class MenuLinkParent extends MigrationLookup {
 
   /**
+   * The menu link plugin manager.
+   *
    * @var \Drupal\Core\Menu\MenuLinkManagerInterface
    */
   protected $menuLinkManager;
 
   /**
-   * @var \Drupal\migrate\Plugin\MigrateProcessInterface
-   */
-  protected $migrationPlugin;
-
-  /**
+   * The menu link entity storage handler.
+   *
    * @var \Drupal\Core\Entity\EntityStorageInterface
    */
   protected $menuLinkStorage;
@@ -41,9 +73,19 @@ class MenuLinkParent extends ProcessPluginBase implements ContainerFactoryPlugin
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateProcessInterface $migration_plugin, MenuLinkManagerInterface $menu_link_manager, EntityStorageInterface $menu_link_storage) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->migrationPlugin = $migration_plugin;
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManagerInterface $process_plugin_manager, MenuLinkManagerInterface $menu_link_manager, EntityStorageInterface $menu_link_storage) {
+    $configuration += [
+      // Find parent menu link IDs already migrated by the current migration.
+      'migration' => $migration->id(),
+    ];
+    parent::__construct(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $migration_plugin_manager,
+      $process_plugin_manager
+    );
     $this->menuLinkManager = $menu_link_manager;
     $this->menuLinkStorage = $menu_link_storage;
   }
@@ -52,51 +94,76 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
-    $migration_configuration['migration'][] = $migration->id();
     return new static(
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('plugin.manager.migrate.process')->createInstance('migration', $migration_configuration, $migration),
+      $migration,
+      $container->get('plugin.manager.migration'),
+      $container->get('plugin.manager.migrate.process'),
       $container->get('plugin.manager.menu.link'),
-      $container->get('entity.manager')->getStorage('menu_link_content')
+      $container->get('entity_type.manager')->getStorage('menu_link_content')
     );
   }
 
   /**
    * {@inheritdoc}
-   *
-   * Find the parent link GUID.
    */
   public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
     $parent_id = array_shift($value);
+
+    // Handle root elements of a menu.
     if (!$parent_id) {
-      // Top level item.
       return '';
     }
+
+    // Try to look up the parent menu link item from the items already migrated.
     try {
-      $already_migrated_id = $this
-        ->migrationPlugin
-        ->transform($parent_id, $migrate_executable, $row, $destination_property);
-      if ($already_migrated_id && ($link = $this->menuLinkStorage->load($already_migrated_id))) {
-        return $link->getPluginId();
-      }
+      $parent_id = parent::transform($parent_id, $migrate_executable, $row, $destination_property);
     }
     catch (MigrateSkipRowException $e) {
-
+      // There are two reasons the exception may have been thrown. Either the
+      // input value was empty -- definitely not the case, since we checked for
+      // that at the top of this method -- or the lookup tried to stub the
+      // parent menu link, but the destination's configuration has 'no_stub' set
+      // to TRUE. In this latter case, we'll just act as if the lookup failed,
+      // and fall back to looking for the parent link using the combination of
+      // menu name  and  parent link path.
+      //
+      // TODO: Introduce a new exception to be thrown if stubbing fails or is
+      // disallowed, and catch that instead.
+      $parent_id = NULL;
+    }
+    if ($parent_id) {
+      return $this->menuLinkStorage->load($parent_id)->getPluginId();
     }
-    if (isset($value[1])) {
-      list($menu_name, $parent_link_path) = $value;
-      $url = Url::fromUserInput("/$parent_link_path");
-      if ($url->isRouted()) {
-        $links = $this->menuLinkManager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters(), $menu_name);
-        if (count($links) == 1) {
-          /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
-          $link = reset($links);
-          return $link->getPluginId();
+
+    // Parent could not be determined by ID so we try to determine by the
+    // combination of the menu name and parent link path.
+    if ($value) {
+      list ($menu_name, $parent_link_path) = $value;
+
+      // If the parent link path is external, URL will be useless because the
+      // link will definitely not correspond to a Drupal route.
+      if (UrlHelper::isExternal($parent_link_path)) {
+        $links = $this->menuLinkStorage->loadByProperties([
+          'menu_name' => $menu_name,
+          'link.uri' => $parent_link_path,
+        ]);
+      }
+      else {
+        $url = Url::fromUserInput('/' . ltrim($parent_link_path, '/'));
+        if ($url->isRouted()) {
+          $links = $this->menuLinkManager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters(), $menu_name);
         }
       }
+
+      if (!empty($links)) {
+        return reset($links)->getPluginId();
+      }
     }
+
+    // Parent could not be determined.
     throw new MigrateSkipRowException();
   }
 
