diff --git a/core/modules/migrate/src/Plugin/Discovery/DependencyFilterDiscoveryDecorator.php b/core/modules/migrate/src/Plugin/Discovery/DependencyFilterDiscoveryDecorator.php
new file mode 100644
index 0000000..e899380
--- /dev/null
+++ b/core/modules/migrate/src/Plugin/Discovery/DependencyFilterDiscoveryDecorator.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\migrate\Plugin\Discovery;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Decorates a discovery object to remove definitions with missing dependencies.
+ *
+ * @ingroup migration
+ */
+class DependencyFilterDiscoveryDecorator implements DiscoveryInterface {
+
+  use DiscoveryTrait;
+
+  /**
+   * The decorated discovery.
+   *
+   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
+   */
+  protected $discovery;
+
+  /**
+   * The module handler to invoke the alter hook.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a new MigrateContainerDerivativeDiscoveryDecorator.
+   *
+   * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
+   *   The parent object that is being decorated.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(DiscoveryInterface $decorated, ModuleHandlerInterface $module_handler) {
+    $this->discovery = $decorated;
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function getDefinitions() {
+    $definitions = $this->discovery->getDefinitions();
+    return array_filter($definitions, function ($definition) {
+      // Exclude plugin definitions that have a provider that is not installed.
+      if (isset($definition['provider']) && !in_array($definition['provider'], ['core', 'component']) && !$this->moduleHandler->moduleExists($definition['provider'])) {
+        return FALSE;
+      }
+      // Exclude plugin definitions that are tagged with Drupal 6 or Drupal X
+      // (where X is a number) and the migrate_drupal module is not installed.
+      if (isset($definition['migration_tags'])) {
+        $is_drupal_to_drupal = array_reduce($definition['migration_tags'], function ($carry , $item ) {
+          // Once $carry is TRUE then the migration plugin is for a Drupal to
+          // Drupal migration. Therefore, there's no need to do anymore regular
+          // expression matching.
+          return $carry || (bool) preg_match('/^Drupal \d/i', $item);
+        }, FALSE);
+        if ($is_drupal_to_drupal && !$this->moduleHandler->moduleExists('migrate_drupal')) {
+          return FALSE;
+        }
+      }
+      return TRUE;
+    });
+  }
+
+}
diff --git a/core/modules/migrate/src/Plugin/MigrationPluginManager.php b/core/modules/migrate/src/Plugin/MigrationPluginManager.php
index d082c11..3c10d9e 100644
--- a/core/modules/migrate/src/Plugin/MigrationPluginManager.php
+++ b/core/modules/migrate/src/Plugin/MigrationPluginManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Plugin\Discovery\YamlDirectoryDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\migrate\MigrateBuildDependencyInterface;
+use Drupal\migrate\Plugin\Discovery\DependencyFilterDiscoveryDecorator;
 
 /**
  * Plugin manager for migration plugins.
@@ -68,7 +69,8 @@ protected function getDiscovery() {
       }, $this->moduleHandler->getModuleDirectories());
 
       $yaml_discovery = new YamlDirectoryDiscovery($directories, 'migrate');
-      $this->discovery = new ContainerDerivativeDiscoveryDecorator($yaml_discovery);
+      $dependency_filter_discovery_decorator = new DependencyFilterDiscoveryDecorator($yaml_discovery, $this->moduleHandler);
+      $this->discovery = new ContainerDerivativeDiscoveryDecorator($dependency_filter_discovery_decorator);
     }
     return $this->discovery;
   }
diff --git a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginListTest.php b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginListTest.php
new file mode 100644
index 0000000..e0b4175
--- /dev/null
+++ b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationPluginListTest.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\Tests\migrate\Kernel\Plugin;
+
+use Drupal\Core\Database\Database;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the migration manager plugin.
+ *
+ * @coversDefaultClass \Drupal\migrate\Plugin\MigratePluginManager
+ * @group migrate
+ */
+class MigrationPluginListTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'migrate',
+    // Test with all modules containing Drupal migrations.
+    'action',
+    'aggregator',
+    'ban',
+    'block',
+    'block_content',
+    'book',
+    'comment',
+    'contact',
+    'dblog',
+    'field',
+    'file',
+    'filter',
+    'forum',
+    'image',
+    'language',
+    'locale',
+    'menu_link_content',
+    'menu_ui',
+    'node',
+    'path',
+    'search',
+    'shortcut',
+    'simpletest',
+    'statistics',
+    'syslog',
+    'system',
+    'taxonomy',
+    'text',
+    'tracker',
+    'update',
+    'user',
+  ];
+
+  /**
+   * Tests MigratePluginManager::getDefinitions()
+   *
+   * @covers ::getDefinitions
+   */
+  public function testGetDefinitions() {
+    // Make sure retrieving all the core migration plugins does not throw any
+    // errors.
+    $migration_plugins = $this->container->get('plugin.manager.migration')->getDefinitions();
+    // All the plugins provided by core depend on migrate_drupal.
+    $this->assertEmpty($migration_plugins);
+
+    // Enable migrate_drupal to test that the plugins can now be discovered.
+    $this->enableModules(['migrate_drupal']);
+    // Set up a migrate database connection so that plugin disocovery works.
+    // Clone the current connection and replace the current prefix.
+    $connection_info = Database::getConnectionInfo('migrate');
+    if ($connection_info) {
+      Database::renameConnection('migrate', 'simpletest_original_migrate');
+    }
+    $connection_info = Database::getConnectionInfo('default');
+    foreach ($connection_info as $target => $value) {
+      $prefix = is_array($value['prefix']) ? $value['prefix']['default'] : $value['prefix'];
+      // Simpletest uses 7 character prefixes at most so this can't cause
+      // collisions.
+      $connection_info[$target]['prefix']['default'] = $prefix . '0';
+
+      // Add the original simpletest prefix so SQLite can attach its database.
+      // @see \Drupal\Core\Database\Driver\sqlite\Connection::init()
+      $connection_info[$target]['prefix'][$value['prefix']['default']] = $value['prefix']['default'];
+    }
+    Database::addConnectionInfo('migrate', 'default', $connection_info['default']);
+
+    $migration_plugins = $this->container->get('plugin.manager.migration')->getDefinitions();
+    // All the plugins provided by core depend on migrate_drupal.
+    $this->assertNotEmpty($migration_plugins);
+  }
+
+}
