diff --git a/core/modules/filter/migration_templates/d7_filter_format.yml b/core/modules/filter/migration_templates/d7_filter_format.yml
new file mode 100755
index 0000000000000000000000000000000000000000..474b0d4d554ba7d4564f10ef090b88c2bf1121bb
--- /dev/null
+++ b/core/modules/filter/migration_templates/d7_filter_format.yml
@@ -0,0 +1,21 @@
+id: d7_filter_format
+label: Drupal 7 filter format configuration
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_filter_format
+process:
+  format:
+    -
+      plugin: machine_name
+      source: name
+    -
+      plugin: dedupe_entity
+      entity_type: filter_format
+      field: format
+      length: 32
+  name: name
+  cache: cache
+  filters: filters
+destination:
+  plugin: entity:filter_format
diff --git a/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php b/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
index 6d99e05ec43ad96f36f6c0caa1825e3a78838a23..b84444c4d988779a4267cf370cbe639f1ccac860 100644
--- a/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
+++ b/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
@@ -11,7 +11,7 @@
 use Drupal\migrate\Row;
 
 /**
- * Drupal 6 role source from database.
+ * Drupal 6 filter source from database.
  *
  * @MigrateSource(
  *   id = "d6_filter_format"
@@ -23,10 +23,7 @@ class FilterFormat extends DrupalSqlBase {
    * {@inheritdoc}
    */
   public function query() {
-    $query = $this->select('filter_formats', 'f')
-      ->fields('f', array('format', 'name', 'roles', 'cache'))
-      ->orderBy('format');
-    return $query;
+    return $this->select('filter_formats', 'f')->fields('f');
   }
 
   /**
@@ -35,9 +32,10 @@ public function query() {
   public function fields() {
     return array(
       'format' => $this->t('Format ID.'),
-      'name' => $this->t('The name of the filter format.'),
-      'roles' => $this->t('The user roles that can use the format.'),
-      'cache' => $this->t('Flag to indicate whether format is cacheable. (1 = cacheable, 0 = not cacheable).'),
+      'name' => $this->t('The name of the format.'),
+      'cache' => $this->t('Whether the format is cacheable.'),
+      'roles' => $this->t('The role IDs which can use the format.'),
+      'filters' => $this->t('The filters configured for the format.'),
     );
   }
 
@@ -50,8 +48,7 @@ public function prepareRow(Row $row) {
     $row->setSourceProperty('roles', array_values(array_filter(explode(',', $roles))));
     $format = $row->getSourceProperty('format');
     // Find filters for this row.
-    $results = $this->database
-      ->select('filters', 'f', array('fetch' => \PDO::FETCH_ASSOC))
+    $results = $this->select('filters', 'f')
       ->fields('f', array('module', 'delta', 'weight'))
       ->condition('format', $format)
       ->execute();
diff --git a/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php b/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php
new file mode 100755
index 0000000000000000000000000000000000000000..06f4c6d96978960af908437ff94c812ce4fa3f78
--- /dev/null
+++ b/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\filter\Plugin\migrate\source\d7\FilterFormat.
+ */
+
+namespace Drupal\filter\Plugin\migrate\source\d7;
+
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+use Drupal\migrate\Row;
+
+/**
+ * Drupal 7 filter source from database.
+ *
+ * @MigrateSource(
+ *   id = "d7_filter_format"
+ * )
+ */
+class FilterFormat extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->select('filter_format', 'f')->fields('f');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'format' => $this->t('Format ID.'),
+      'name' => $this->t('The name of the format.'),
+      'cache' => $this->t('Whether the format is cacheable.'),
+      'status' => $this->t('The status of the format'),
+      'weight' => $this->t('The weight of the format'),
+      'filters' => $this->t('The filters configured for the format.'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    // Find filters for this format.
+    $filters = $this->select('filter', 'f')
+      ->fields('f')
+      ->condition('format', $row->getSourceProperty('format'))
+      ->condition('status', 1)
+      ->execute()
+      ->fetchAllAssoc('name');
+
+    foreach ($filters as $id => $filter) {
+      $filters[$id]['settings'] = unserialize($filter['settings']);
+    }
+    $row->setSourceProperty('filters', $filters);
+
+    return parent::prepareRow($row);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['format']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/filter/src/Tests/Migrate/d7/MigrateFilterFormatTest.php b/core/modules/filter/src/Tests/Migrate/d7/MigrateFilterFormatTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ffb3ea57dd8f817ffed4de85dd62a0b2f469a8a7
--- /dev/null
+++ b/core/modules/filter/src/Tests/Migrate/d7/MigrateFilterFormatTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\filter\Tests\Migrate\d7\MigrateFilterFormatTest.
+ */
+
+namespace Drupal\filter\Tests\Migrate\d7;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\filter\FilterFormatInterface;
+use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase;
+
+/**
+ * Upgrade variables to filter.formats.*.yml.
+ *
+ * @group filter
+ */
+class MigrateFilterFormatTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  static $modules = array('filter');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->loadDumps(['Filter.php', 'FilterFormat.php', 'Variable.php']);
+    $this->executeMigration('d7_filter_format');
+  }
+
+  /**
+   * Asserts various aspects of a filter format entity.
+   *
+   * @param string $id
+   *   The format ID.
+   * @param string $label
+   *   The expected label of the format.
+   * @param array $enabled_filters
+   *   The expected filters in the format, keyed by ID.
+   */
+  protected function assertEntity($id, $label, array $enabled_filters) {
+    /** @var \Drupal\filter\FilterFormatInterface $entity */
+    $entity = FilterFormat::load($id);
+    $this->assertTrue($entity instanceof FilterFormatInterface);
+    $this->assertIdentical($label, $entity->label());
+    // get('filters') will return enabled filters only, not all of them.
+    $this->assertIdentical($enabled_filters, array_keys($entity->get('filters')));
+  }
+
+  /**
+   * Tests the Drupal 7 filter format to Drupal 8 migration.
+   */
+  public function testFilterFormat() {
+    $this->assertEntity('custom_text_format', 'Custom Text format', ['filter_autop', 'filter_html']);
+    $this->assertEntity('filtered_html', 'Filtered HTML', ['filter_autop', 'filter_html', 'filter_htmlcorrector', 'filter_url']);
+    $this->assertEntity('full_html', 'Full HTML', ['filter_autop', 'filter_htmlcorrector', 'filter_url']);
+    $this->assertEntity('plain_text', 'Plain text', ['filter_autop', 'filter_html_escape', 'filter_url']);
+
+    // Ensure that filter-specific settings were migrated.
+    /** @var \Drupal\filter\FilterFormatInterface $format */
+    $format = FilterFormat::load('filtered_html');
+    $config = $format->filters('filter_html')->getConfiguration();
+    $this->assertIdentical('<div> <span> <ul> <li>', $config['settings']['allowed_html']);
+    $config = $format->filters('filter_url')->getConfiguration();
+    $this->assertIdentical(128, $config['settings']['filter_url_length']);
+  }
+
+}
diff --git a/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d6/FilterFormatTest.php b/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d6/FilterFormatTest.php
index ebdb776bb0a45487616f5b973171efd05fb414a6..9d27e4e98b99f9917cb810556058a6b9e0bbb26d 100644
--- a/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d6/FilterFormatTest.php
+++ b/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d6/FilterFormatTest.php
@@ -10,17 +10,14 @@
 use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
 
 /**
- * Tests D6 filter_formats table source plugin.
+ * Tests d6_filter_format source plugin.
  *
  * @group filter
  */
 class FilterFormatTest extends MigrateSqlSourceTestCase {
 
-  // The plugin system is not working during unit testing so the source plugin
-  // class needs to be manually specified.
   const PLUGIN_CLASS = 'Drupal\filter\Plugin\migrate\source\d6\FilterFormat';
 
-  // The fake Migration configuration entity.
   protected $migrationConfiguration = array(
     'id' => 'test',
     'highWaterProperty' => array('field' => 'test'),
diff --git a/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d7/FilterFormatTest.php b/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d7/FilterFormatTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..06d8d6b6383dc553e993838bd97d3c05174d53ff
--- /dev/null
+++ b/core/modules/filter/tests/src/Unit/Plugin/migrate/source/d7/FilterFormatTest.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\filter\Unit\Plugin\migrate\source\d7\FilterFormatTest.
+ */
+
+namespace Drupal\Tests\filter\Unit\Plugin\migrate\source\d7;
+
+use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+/**
+ * Tests d7_filter_format source plugin.
+ *
+ * @group filter
+ */
+class FilterFormatTest extends MigrateSqlSourceTestCase {
+
+  const PLUGIN_CLASS = 'Drupal\filter\Plugin\migrate\source\d7\FilterFormat';
+
+  protected $migrationConfiguration = array(
+    'id' => 'test',
+    'source' => array(
+      'plugin' => 'd6_filter_formats',
+    ),
+  );
+
+  protected $expectedResults = array(
+    array(
+      'format' => 'custom_text_format',
+      'name' => 'Custom Text format',
+      'cache' => 1,
+      'status' => 1,
+      'weight' => 0,
+      'filters' => array(
+        'filter_autop' => array(
+          'module' => 'filter',
+          'name' => 'filter_autop',
+          'weight' => 0,
+          'status' => 1,
+          'settings' => array(),
+        ),
+        'filter_html' => array(
+          'module' => 'filter',
+          'name' => 'filter_html',
+          'weight' => 1,
+          'status' => 1,
+          'settings' => array(),
+        ),
+      ),
+    ),
+    array(
+      'format' => 'full_html',
+      'name' => 'Full HTML',
+      'cache' => 1,
+      'status' => 1,
+      'weight' => 1,
+      'filters' => array(
+        'filter_url' => array(
+          'module' => 'filter',
+          'name' => 'filter_url',
+          'weight' => 0,
+          'status' => 1,
+          'settings' => array(),
+        ),
+      ),
+    ),
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    foreach ($this->expectedResults as $row) {
+      foreach ($row['filters'] as $filter) {
+        $filter['format'] = $row['format'];
+        $filter['settings'] = serialize($filter['settings']);
+        $this->databaseContents['filter'][] = $filter;
+      }
+      unset($row['filters']);
+      $this->databaseContents['filter_format'][] = $row;
+    }
+    parent::setUp();
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/Table/d7/Filter.php b/core/modules/migrate_drupal/src/Tests/Table/d7/Filter.php
index 29fa2bac498b34a8c6052ba00a0991e69e2b6ddc..e6de77e5a83a1e7f248fb93ab24f28b31c046030 100644
--- a/core/modules/migrate_drupal/src/Tests/Table/d7/Filter.php
+++ b/core/modules/migrate_drupal/src/Tests/Table/d7/Filter.php
@@ -119,7 +119,7 @@ public function load() {
       'name' => 'filter_html',
       'weight' => '1',
       'status' => '1',
-      'settings' => 'a:3:{s:12:"allowed_html";s:74:"<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>";s:16:"filter_html_help";i:1;s:20:"filter_html_nofollow";i:0;}',
+      'settings' => 'a:3:{s:12:"allowed_html";s:22:"<div> <span> <ul> <li>";s:16:"filter_html_help";i:1;s:20:"filter_html_nofollow";i:0;}',
     ))->values(array(
       'format' => 'filtered_html',
       'module' => 'filter',
@@ -140,7 +140,7 @@ public function load() {
       'name' => 'filter_url',
       'weight' => '0',
       'status' => '1',
-      'settings' => 'a:1:{s:17:"filter_url_length";i:72;}',
+      'settings' => 'a:1:{s:17:"filter_url_length";s:3:"128";}',
     ))->values(array(
       'format' => 'full_html',
       'module' => 'filter',
@@ -215,4 +215,4 @@ public function load() {
   }
 
 }
-#26810a92f8dcd637a67b91e218441083
+#d47ad1c59579daa0db744321977c5e4b