diff --git a/core/modules/migrate/config/schema/migrate.schema.yml b/core/modules/migrate/config/schema/migrate.schema.yml
index c48bdd1..d1c4bff 100644
--- a/core/modules/migrate/config/schema/migrate.schema.yml
+++ b/core/modules/migrate/config/schema/migrate.schema.yml
@@ -13,6 +13,9 @@ migrate.migration.*:
       sequence:
         type: string
         label: 'Group'
+    migration_group:
+      type: string
+      label: 'Active group'
     label:
       type: label
       label: 'Label'
@@ -44,3 +47,20 @@ migrate.migration.*:
           sequence:
             type: string
             label: 'Dependency'
+
+migrate.migration_group.*:
+  type: config_entity
+  label: 'Migration Group'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    module:
+      type: string
+      label: 'Dependent module'
+    shared_configuration:
+      type: ignore
+      label: 'Shared migration configuration'
diff --git a/core/modules/migrate/src/Entity/MigrationGroup.php b/core/modules/migrate/src/Entity/MigrationGroup.php
new file mode 100644
index 0000000..9fd8bf9
--- /dev/null
+++ b/core/modules/migrate/src/Entity/MigrationGroup.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Entity\MigrationGroup.
+ */
+
+namespace Drupal\migrate\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the Migration Group entity.
+ *
+ * The migration group entity is used to group active migrations, as well as to
+ * store shared migration configuration.
+ *
+ * @ConfigEntityType(
+ *   id = "migration_group",
+ *   label = @Translation("Migration Group"),
+ *   module = "migrate",
+ *   handlers = {
+ *   },
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label"
+ *   }
+ * )
+ */
+class MigrationGroup extends ConfigEntityBase implements MigrationGroupInterface {
+
+  /**
+   * The migration group ID (machine name).
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The human-readable label for the migration group.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    // Delete all migrations contained in this group.
+    $query = \Drupal::entityQuery('migration')
+      ->condition('migration_group', $this->id());
+    $names = $query->execute();
+
+    // Order the migrations according to their dependencies.
+    /** @var MigrationInterface[] $migrations */
+    $migrations = \Drupal::entityManager()->getStorage('migration')->loadMultiple($names);
+
+    // Delete in reverse order, so dependencies are never violated.
+    $migrations = array_reverse($migrations);
+
+    foreach ($migrations as $migration) {
+      $migration->delete();
+    }
+
+    // Finally, delete the group itself.
+    parent::delete();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    parent::calculateDependencies();
+    // Make sure we save any explicit module dependencies.
+    if ($provider = $this->get('module')) {
+      $this->addDependency('module', $provider);
+    }
+    return $this->dependencies;
+  }
+
+}
diff --git a/core/modules/migrate/src/Entity/MigrationGroupInterface.php b/core/modules/migrate/src/Entity/MigrationGroupInterface.php
new file mode 100644
index 0000000..7461477
--- /dev/null
+++ b/core/modules/migrate/src/Entity/MigrationGroupInterface.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Entity\MigrationGroupInterface.
+ */
+
+namespace Drupal\migrate\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Interface for migration groups.
+ */
+interface MigrationGroupInterface extends ConfigEntityInterface {
+
+}
diff --git a/core/modules/migrate/src/MigrationStorage.php b/core/modules/migrate/src/MigrationStorage.php
index 3d0454e..529535e 100644
--- a/core/modules/migrate/src/MigrationStorage.php
+++ b/core/modules/migrate/src/MigrationStorage.php
@@ -8,7 +8,15 @@
 namespace Drupal\migrate;
 
 use Drupal\Component\Graph\Graph;
+use Drupal\Component\Uuid\UuidInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Entity\MigrationGroupInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Storage for migration entities.
@@ -16,6 +24,49 @@
 class MigrationStorage extends ConfigEntityStorage implements MigrateBuildDependencyInterface {
 
   /**
+   * The migration group storage.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $migrationGroupStorage;
+
+  /**
+   * Constructs a MigrationStorage object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type definition.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory service.
+   * @param \Drupal\Component\Uuid\UuidInterface $uuid_service
+   *   The UUID service.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $migration_group_storage
+   *   The migration group storage.
+   */
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityStorageInterface $migration_group_storage) {
+    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
+
+    $this->configFactory = $config_factory;
+    $this->uuidService = $uuid_service;
+    $this->languageManager = $language_manager;
+    $this->migrationGroupStorage = $migration_group_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
+    return new static(
+      $entity_type,
+      $container->get('config.factory'),
+      $container->get('uuid'),
+      $container->get('language_manager'),
+      $container->get('entity_manager')->getStorage('migration_group')
+    );
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function buildDependencyMigration(array $migrations, array $dynamic_ids) {
@@ -90,4 +141,42 @@ protected function addDependency(array &$graph, $id, $dependency, $dynamic_ids)
     $graph[$id]['edges'] += array_combine($dependencies, $dependencies);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function doLoadMultiple(array $ids = NULL) {
+    $migrations = parent::doLoadMultiple($ids);
+
+    /** @var MigrationInterface $migration */
+    foreach ($migrations as $migration) {
+      // If we are pointing to a valid group, merge its properties into ours.
+      if (isset($migration->migration_group)) {
+        /** @var MigrationGroupInterface $group */
+        $group = $this->migrationGroupStorage->load($migration->migration_group);
+        if ($group) {
+          $shared_configuration = $group->get('shared_configuration');
+          if ($shared_configuration) {
+            foreach ($shared_configuration as $key => $group_value) {
+              $migration_value = $migration->get($key);
+              // Where both the migration and the group provide arrays,
+              // replace recursively (so each key collision is resolved in favor
+              // of the migration).
+              if (is_array($migration_value) && is_array($group_value)) {
+                $merged_values = array_replace_recursive($group_value, $migration_value);
+                $migration->set($key, $merged_values);
+              }
+              // Where the group provides a value the migration doesn't, use
+              // the group value.
+              elseif (is_null($migration_value)) {
+                $migration->set($key, $group_value);
+              }
+              // Otherwise, the existing migration value overrides the group value.
+            }
+          }
+        }
+      }
+    }
+    return $migrations;
+  }
+
 }
diff --git a/core/modules/migrate/src/Tests/MigrationGroupTest.php b/core/modules/migrate/src/Tests/MigrationGroupTest.php
new file mode 100644
index 0000000..95b6e49
--- /dev/null
+++ b/core/modules/migrate/src/Tests/MigrationGroupTest.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\MigrationGroupTest.
+ */
+
+namespace Drupal\migrate\Tests;
+
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Entity\MigrationGroupInterface;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Test migration groups.
+ *
+ * @group migrate
+ */
+class MigrationGroupTest extends WebTestBase {
+
+  public static $modules = array('migrate');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->strictConfigSchema = FALSE;
+    parent::setUp();
+  }
+
+  /**
+   * Test that group configuration is properly merged into specific migrations.
+   */
+  public function testConfigurationMerge() {
+    $group_id = 'test_group';
+
+    /** @var MigrationGroupInterface $migration_group */
+    $migration_group = entity_create('migration_group', array());
+    $migration_group->set('id', $group_id);
+    $migration_group->set('shared_configuration', array(
+      'migration_groups' => array('Drupal 6'), // In migration, so will be overrideen.
+      'source' => array(
+        'constants' => array(
+          'type' => 'image',    // Not in migration, so will be added.
+          'cardinality' => '1', // In migration, so will be overridden.
+        ),
+      ),
+      'destination' => array('entity' => 'field_storage_config'), // Not in migration, so will be added.
+    ));
+    $migration_group->save();
+
+    /** @var MigrationInterface $migration */
+    $migration = entity_create('migration', array());
+    $migration->set('id', 'specific_migration');
+    $migration->set('migration_group', $group_id);
+    $migration->set('label', 'Unaffected by the group');
+    $migration->set('migration_groups', array('Drupal 7')); // Overrides group.
+    $migration->set('source', array(
+      'plugin' => 'empty',        // Not in group, persists.
+      'constants' => array(
+        'entity_type' => 'user',  // Not in group, persists.
+        'cardinality' => '3',     // Overrides group.
+      ),
+    ));
+    $migration->save();
+
+    $expected_config = array(
+      'migration_group' => $group_id,
+      'label' => 'Unaffected by the group',
+      'migration_groups' => array('Drupal 7'),
+      'source' => array(
+        'plugin' => 'empty',
+        'constants' => array(
+          'entity_type' => 'user',
+          'type' => 'image',
+          'cardinality' => '3',
+        ),
+      ),
+      'destination' => array('entity' => 'field_storage_config'),
+    );
+    /** @var MigrationInterface $loaded_migration */
+    $loaded_migration = entity_load('migration', 'specific_migration', TRUE);
+    foreach ($expected_config as $key => $expected_value) {
+      $actual_value = $loaded_migration->get($key);
+      $this->assertEqual($expected_value, $actual_value);
+    }
+  }
+
+  /**
+   * Test that deleting a group deletes its migrations.
+   */
+  public function testDelete() {
+    /** @var MigrationGroupInterface $migration_group */
+    $migration_group = entity_create('migration_group', array());
+    $migration_group->set('id', 'test_group');
+    $migration_group->save();
+
+    /** @var MigrationInterface $migration */
+    $migration = entity_create('migration', array());
+    $migration->set('id', 'specific_migration');
+    $migration->set('migration_group', 'test_group');
+    $migration->save();
+
+    /** @var MigrationGroupInterface $loaded_migration_group */
+    $loaded_migration_group = entity_load('migration_group', 'test_group', TRUE);
+    $loaded_migration_group->delete();
+
+    /** @var MigrationGroupInterface $loaded_migration */
+    $loaded_migration = entity_load('migration', 'specific_migration', TRUE);
+    $this->assertNull($loaded_migration);
+  }
+
+}
