diff --git a/core/modules/migrate/src/MigrateExecutable.php b/core/modules/migrate/src/MigrateExecutable.php
index d5b9d1a..ae04563 100644
--- a/core/modules/migrate/src/MigrateExecutable.php
+++ b/core/modules/migrate/src/MigrateExecutable.php
@@ -103,10 +103,9 @@ class MigrateExecutable implements MigrateExecutableInterface {
    * @throws \Drupal\migrate\MigrateException
    */
   public function __construct(MigrationInterface $migration, MigrateMessageInterface $message = NULL, EventDispatcherInterface $event_dispatcher = NULL) {
-    $this->migration = $migration;
     $this->message = $message ?: new MigrateMessage();
-    $this->migration->getIdMap()->setMessage($this->message);
     $this->eventDispatcher = $event_dispatcher;
+    $this->setMigration($migration);
     // Record the memory limit in bytes
     $limit = trim(ini_get('memory_limit'));
     if ($limit == '-1') {
@@ -118,6 +117,14 @@ public function __construct(MigrationInterface $migration, MigrateMessageInterfa
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function setMigration(MigrationInterface $migration) {
+    $this->migration = $migration;
+    $this->migration->getIdMap()->setMessage($this->message);
+  }
+
+  /**
    * Returns the source.
    *
    * Makes sure source is initialized based on migration settings.
diff --git a/core/modules/migrate/src/MigrateExecutableInterface.php b/core/modules/migrate/src/MigrateExecutableInterface.php
index 33d5914..e1d686e 100644
--- a/core/modules/migrate/src/MigrateExecutableInterface.php
+++ b/core/modules/migrate/src/MigrateExecutableInterface.php
@@ -7,6 +7,11 @@
 interface MigrateExecutableInterface {
 
   /**
+   * Sets the current migration.
+   */
+  public function setMigration(MigrationInterface $migration);
+
+  /**
    * Performs an import operation - migrate items from source to destination.
    */
   public function import();
diff --git a/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
index 22c17ca..6e095e2 100644
--- a/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
+++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
@@ -3,6 +3,7 @@
 namespace Drupal\migrate\Plugin\migrate\process;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\MigrateSkipRowException;
 use Drupal\migrate\MigrateSkipProcessException;
 use Drupal\migrate\Plugin\MigratePluginManagerInterface;
 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
@@ -161,15 +162,14 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     if (!is_array($migration_ids)) {
       $migration_ids = [$migration_ids];
     }
-    $self = FALSE;
+
     /** @var \Drupal\migrate\Plugin\MigrationInterface[] $migrations */
+    $migrations = $this->migrationPluginManager->createInstances($migration_ids);
+
+    // Lookup the destination ids.
     $destination_ids = NULL;
     $source_id_values = [];
-    $migrations = $this->migrationPluginManager->createInstances($migration_ids);
     foreach ($migrations as $migration_id => $migration) {
-      if ($migration_id == $this->migration->id()) {
-        $self = TRUE;
-      }
       if (isset($this->configuration['source_ids'][$migration_id])) {
         $configuration = ['source' => $this->configuration['source_ids'][$migration_id]];
         $value = $this->processPluginManager
@@ -187,40 +187,67 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       }
     }
 
-    if (!$destination_ids && !empty($this->configuration['no_stub'])) {
-      return NULL;
+    // If the lookup didn't succeed, try and create a stub record.
+    if (!$destination_ids && (empty($this->configuration['no_stub']))) {
+      $destination_ids = $this->createStubRecord($source_id_values, $migrations, $migrate_executable);
     }
 
-    if (!$destination_ids && ($self || isset($this->configuration['stub_id']) || count($migrations) == 1)) {
-      // If the lookup didn't succeed, figure out which migration will do the
-      // stubbing.
-      if ($self) {
-        $migration = $this->migration;
-      }
-      elseif (isset($this->configuration['stub_id'])) {
-        $migration = $migrations[$this->configuration['stub_id']];
-      }
-      else {
-        $migration = reset($migrations);
+    if ($destination_ids) {
+      if (count($destination_ids) == 1) {
+        $destination_ids = reset($destination_ids);
       }
+    }
+    else {
+      $destination_ids = NULL;
+    }
+    return $destination_ids;
+  }
+  /**
+   * Skips the migration process entirely if the value is FALSE.
+   *
+   * @param mixed $value
+   *   The incoming value to transform.
+   *
+   * @throws \Drupal\migrate\MigrateSkipProcessException
+   */
+  protected function skipOnEmpty(array $value) {
+    if (!array_filter($value)) {
+      throw new MigrateSkipProcessException();
+    }
+  }
+  /**
+   * Creates a stub record.
+   *
+   * @param array $source_id_values
+   *   The source identifier keyed values of the record, e.g. ['nid' => 5].
+   * @param array $migrations
+   *   List of migrations in the plugin configuration.
+   * @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
+   *   The migration in which this process is being executed.
+   *
+   * @return array|null An array of the stub record identifier values.
+   * An array of the stub record identifier values.
+   */
+  protected function createStubRecord(array $source_id_values, array $migrations, MigrateExecutableInterface $migrate_executable) {
+    $destination_ids = NULL;
+    $migration = $this->getStubbingMigration($migrations);
+    if ($migration) {
+      $stub_row = $this->createStubRow($migration, $source_id_values);
+
       $destination_plugin = $migration->getDestinationPlugin(TRUE);
       // Only keep the process necessary to produce the destination ID.
       $process = $migration->getProcess();
 
-      // We already have the source ID values but need to key them for the Row
-      // constructor.
-      $source_ids = $migration->getSourcePlugin()->getIds();
-      $values = [];
-      foreach (array_keys($source_ids) as $index => $source_id) {
-        $values[$source_id] = $source_id_values[$migration->id()][$index];
+      $id_map = $migration->getIdMap();
+      $migrate_executable->setMigration($migration);
+      try {
+        $migrate_executable->processRow($stub_row, $process);
       }
+      catch (MigrateSkipRowException $e) {
+        // Process pipeline failed.
+      }
+      $migrate_executable->setMigration($this->migration);
 
-      $stub_row = $this->createStubRow($values + $migration->getSourceConfiguration(), $source_ids);
-
-      // Do a normal migration with the stub row.
-      $migrate_executable->processRow($stub_row, $process);
-      $destination_ids = [];
-      $id_map = $migration->getIdMap();
       try {
         $destination_ids = $destination_plugin->import($stub_row);
       }
@@ -231,29 +258,38 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       if ($destination_ids) {
         $id_map->saveIdMapping($stub_row, $destination_ids, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
       }
-    }
-    if ($destination_ids) {
-      if (count($destination_ids) == 1) {
-        return reset($destination_ids);
-      }
       else {
-        return $destination_ids;
+        $destination_ids = NULL;
       }
     }
+
+    return $destination_ids;
   }
 
   /**
-   * Skips the migration process entirely if the value is FALSE.
+   * Obtains the migration to create a stub row.
    *
-   * @param mixed $value
-   *   The incoming value to transform.
+   * @param array $migrations
+   *   List of migrations in the plugin configuration.
    *
-   * @throws \Drupal\migrate\MigrateSkipProcessException
+   * @return \Drupal\migrate\Plugin\MigrationInterface
+   *   The migration to use for the stub row.
    */
-  protected function skipOnEmpty(array $value) {
-    if (!array_filter($value)) {
-      throw new MigrateSkipProcessException();
+  protected function getStubbingMigration(array $migrations) {
+    // Prefer self in the first instance.
+    if (array_key_exists($this->migration->id(), $migrations)) {
+      $migration = $this->migration;
     }
+    elseif (isset($this->configuration['stub_id'])) {
+      $migration = $migrations[$this->configuration['stub_id']];
+    }
+    elseif (count($migrations) == 1) {
+      $migration = reset($migrations);
+    }
+    else {
+      $migration = NULL;
+    }
+    return $migration;
   }
 
   /**
@@ -262,16 +298,23 @@ protected function skipOnEmpty(array $value) {
    * This simple wrapper of the Row constructor allows sub-classing plugins to
    * have more control over the row.
    *
-   * @param array $values
-   *   An array of values to add as properties on the object.
-   * @param array $source_ids
-   *   An array containing the IDs of the source using the keys as the field
-   *   names.
-   *
-   * @return \Drupal\migrate\Row
+   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
+   *   The migration entity.
+   * @param array $source_id_values
+   *   The source identifier keyed values of the record, e.g. ['nid' => 5].
+   * @return \Drupal\migrate\Row The stub row.
    *   The stub row.
    */
-  protected function createStubRow(array $values, array $source_ids) {
+  protected function createStubRow(MigrationInterface $migration, array $source_id_values) {
+    // We already have the source ID values but need to key them for the Row
+    // constructor.
+    $source_ids = $migration->getSourcePlugin()->getIds();
+    $values = [];
+    foreach (array_keys($source_ids) as $index => $source_id) {
+      $values[$source_id] = $source_id_values[$migration->id()][$index];
+    }
+    $values += $migration->getSourceConfiguration();
+
     return new Row($values, $source_ids, TRUE);
   }
 
