diff --git a/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
index 862f114a5d..d911feacae 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\MigrateException;
 use Drupal\migrate\MigrateSkipProcessException;
 use Drupal\migrate\Plugin\MigratePluginManagerInterface;
 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
@@ -31,6 +32,14 @@
  *   any stub entities.
  * - no_stub: (optional) Prevents the creation of a stub entity when no
  *   relationship is found in the migration map.
+ * - return_associative: (bool) Forces the plugin to return destination ids in
+ *   an associative array, keyed as defined by the destination plugin.
+ *   Prior to 8.6 the default behavior was to return a scaler if the destination
+ *   plugin only had one id, and an indexed array if the lookup succeeded
+ *   and there were multiple destination ids.  Beginning in 8.7, this behavior
+ *   is depricated and it is required to specify return_associative:true if
+ *   your lookup returns one of the above scenarios.  Beginning in Drupal 9.0
+ *   this will be the default behavior.
  *
  * Examples:
  *
@@ -150,6 +159,11 @@ public static function create(ContainerInterface $container, array $configuratio
    * {@inheritdoc}
    */
   public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    if (isset($this->configuration['return_associative']) && $this->configuration['return_associative'] !== TRUE) {
+      throw new MigrateException("Using a value for return_associative other than true is not supported");
+    }
+
+    $return_associative = isset($this->configuration['return_associative']);
     $lookup_migrations_ids = $this->configuration['migration'];
     if (!is_array($lookup_migrations_ids)) {
       $lookup_migrations_ids = [$lookup_migrations_ids];
@@ -178,6 +192,13 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       $source_id_values[$lookup_migration_id] = $value;
       // Break out of the loop as soon as a destination ID is found.
       if ($destination_ids = $lookup_migration->getIdMap()->lookupDestinationId($source_id_values[$lookup_migration_id])) {
+        if ($return_associative) {
+          $destination_keys = array_keys($lookup_migration->getDestinationPlugin()->getIds());
+          $destination_ids = array_combine($destination_keys, $destination_ids);
+        }
+        else {
+          $this->triggerNonAssociativeReturnDeprecationError();
+        }
         break;
       }
     }
@@ -228,7 +249,8 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       }
     }
     if ($destination_ids) {
-      if (count($destination_ids) == 1) {
+      if (count($destination_ids) == 1  && !$return_associative) {
+        $this->triggerNonAssociativeReturnDeprecationError();
         return reset($destination_ids);
       }
       else {
@@ -270,4 +292,19 @@ protected function createStubRow(array $values, array $source_ids) {
     return new Row($values, $source_ids, TRUE);
   }
 
+  /**
+   * Triggers an error when using deprecated configuration.
+   *
+   * @deprecated It is deprecated in Drupal 8.7.0 to return a scalar or indexed
+   * array from the migrate_lookup plugin. use return_associative: true and
+   * process the resulting associative array instead. This will be the default
+   * behavior beginning in Drupal 9.0
+   *
+   * @see https://www.drupal.org/node/2996553
+   */
+  protected function triggerNonAssociativeReturnDeprecationError() {
+    @trigger_error('It is deprecated in Drupal 8.7.0 to return a scalar or indexed array from the migrate_lookup plugin. use return_associative: true and process the resulting associative array instead. This will be the default behavior beginning in Drupal 9.0. See https://www.drupal.org/node/2996553', E_USER_DEPRECATED);
+
+  }
+
 }
diff --git a/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php b/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
index 9158cdbdbd..f83214bcff 100644
--- a/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
+++ b/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\migrate\Unit\process;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\migrate\MigrateException;
 use Drupal\migrate\MigrateSkipProcessException;
 use Drupal\migrate\Plugin\migrate\process\Get;
 use Drupal\migrate\Plugin\MigrationInterface;
@@ -13,6 +14,7 @@
 use Drupal\migrate\Plugin\MigrateSourceInterface;
 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
 use Drupal\migrate\Row;
+use Drupal\Tests\Traits\ExpectDeprecationTrait;
 use Prophecy\Argument;
 
 /**
@@ -20,6 +22,7 @@
  * @group migrate
  */
 class MigrationLookupTest extends MigrateProcessTestCase {
+  use ExpectDeprecationTrait;
 
   /**
    * @covers ::transform
@@ -112,7 +115,7 @@ public function testSkipOnEmpty() {
   /**
    * Tests a successful lookup.
    *
-   * @dataProvider successfulLookupDataProvider
+   * This tests lookups in the non-associative deprecated format.
    *
    * @param array $source_id_values
    *   The source id(s) of the migration map.
@@ -122,8 +125,11 @@ public function testSkipOnEmpty() {
    *   The source value(s) for the migration process plugin.
    * @param string|array $expected_value
    *   The expected value(s) of the migration process plugin.
+   *
+   * @dataProvider successfulLookupDataProvider
+   * @group legacy
    */
-  public function testSuccessfulLookup($source_id_values, $destination_id_values, $source_value, $expected_value) {
+  public function testSuccessfulLookup(array $source_id_values, array $destination_id_values, $source_value, $expected_value) {
     $migration_plugin = $this->prophesize(MigrationInterface::class);
     $migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
     $process_plugin_manager = $this->prophesize(MigratePluginManager::class);
@@ -146,13 +152,18 @@ public function testSuccessfulLookup($source_id_values, $destination_id_values,
       ->willReturn([$migration_plugin->reveal()]);
 
     $migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
-    $this->assertSame($expected_value, $migration->transform($source_value, $this->migrateExecutable, $this->row, 'foo'));
+
+    $this->expectDeprecation('It is deprecated in Drupal 8.7.0 to return a scalar or indexed array from the migrate_lookup plugin. use return_associative: true and process the resulting associative array instead. This will be the default behavior beginning in Drupal 9.0. See https://www.drupal.org/node/2996553');
+    $actual_value = $migration->transform($source_value, $this->migrateExecutable, $this->row, 'foo');
+
+    $this->assertSame($expected_value, $actual_value);
   }
 
   /**
    * Provides data for the successful lookup test.
    *
    * @return array
+   *   The array of test data.
    */
   public function successfulLookupDataProvider() {
     return [
@@ -203,6 +214,108 @@ public function successfulLookupDataProvider() {
     ];
   }
 
+  /**
+   * Test lookup return as associative array.
+   *
+   * @param array $source_id_values
+   *   The source id(s) of the migration map.
+   * @param array $destination_id_values
+   *   The destination id(s) of the migration map.
+   * @param string|array $source_value
+   *   The source value(s) for the migration process plugin.
+   * @param string|array $expected_value
+   *   The expected value(s) of the migration process plugin.
+   *
+   * @dataProvider successfulLookupAssocDataProvider
+   */
+  public function testSuccessfulLookupAssoc(array $source_id_values, array $destination_id_values, $source_value, $expected_value) {
+    $migration_plugin = $this->prophesize(MigrationInterface::class);
+    $migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
+    $process_plugin_manager = $this->prophesize(MigratePluginManager::class);
+    $destination_plugin = $this->prophesize(MigrateDestinationInterface::class);
+    $destination_keys = ['id1' => [], 'id2' => []];
+
+    $destination_plugin->getIds()->willReturn(array_slice($destination_keys, 0, count($destination_id_values)));
+
+    $configuration = [
+      'migration' => 'foobaz',
+      'return_associative' => TRUE,
+    ];
+    $migration_plugin->id()->willReturn(uniqid());
+
+    $id_map = $this->prophesize(MigrateIdMapInterface::class);
+    $id_map->lookupDestinationId($source_id_values)->willReturn($destination_id_values);
+    $migration_plugin->getIdMap()->willReturn($id_map->reveal());
+    $migration_plugin->getDestinationPlugin()->willReturn($destination_plugin->reveal());
+
+    $migration_plugin_manager->createInstances(['foobaz'])
+      ->willReturn(['foobaz' => $migration_plugin->reveal()]);
+
+    $migrationStorage = $this->prophesize(EntityStorageInterface::class);
+    $migrationStorage
+      ->loadMultiple(['foobaz'])
+      ->willReturn([$migration_plugin->reveal()]);
+
+    $migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
+    $actual_value = $migration->transform($source_value, $this->migrateExecutable, $this->row, 'foo');
+    $this->assertSame($expected_value, $actual_value);
+  }
+
+  /**
+   * Provides data for the successful lookup test.
+   *
+   * @return array
+   *   The data.
+   */
+  public function successfulLookupAssocDataProvider() {
+    return [
+      // Test data for scalar to scalar.
+      [
+        // Source ID of the migration map.
+        [1],
+        // Destination ID of the migration map.
+        [3],
+        // Input value for the migration plugin.
+        1,
+        // Expected output value of the migration plugin.
+        ['id1' => 3],
+      ],
+      // Test data for scalar to array.
+      [
+        // Source ID of the migration map.
+        [1],
+        // Destination IDs of the migration map.
+        [3, 'foo'],
+        // Input value for the migration plugin.
+        1,
+        // Expected output values of the migration plugin.
+        ['id1' => 3, 'id2' => 'foo'],
+      ],
+      // Test data for array to scalar.
+      [
+        // Source IDs of the migration map.
+        [1, 3],
+        // Destination ID of the migration map.
+        ['foo'],
+        // Input values for the migration plugin.
+        [1, 3],
+        // Expected output value of the migration plugin.
+        ['id1' => 'foo'],
+      ],
+      // Test data for array to array.
+      [
+        // Source IDs of the migration map.
+        [1, 3],
+        // Destination IDs of the migration map.
+        [3, 'foo'],
+        // Input values for the migration plugin.
+        [1, 3],
+        // Expected output values of the migration plugin.
+        ['id1' => 3, 'id2' => 'foo'],
+      ],
+    ];
+  }
+
   /**
    * Tests that a message is successfully created if import fails.
    */
@@ -299,4 +412,22 @@ public function testMultipleSourceIds() {
     $this->assertEquals(2, $result);
   }
 
+  /**
+   * Tests that an exception is thrown if return_associative is set to false.
+   */
+  public function testUnsupportedConfig() {
+    $migration_plugin = $this->prophesize(MigrationInterface::class);
+    $migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
+    $process_plugin_manager = $this->prophesize(MigratePluginManager::class);
+    $configuration = [
+      'migration' => 'foobaz',
+      'return_associative' => FALSE,
+    ];
+
+    $migration_plugin = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
+
+    $this->expectException(MigrateException::class);
+    $migration_plugin->transform(1, $this->migrateExecutable, $this->row, 'foo');
+  }
+
 }
