diff --git a/core/modules/filter/filter.admin.inc b/core/modules/filter/filter.admin.inc
index 044fe58..5d7e9cb 100644
--- a/core/modules/filter/filter.admin.inc
+++ b/core/modules/filter/filter.admin.inc
@@ -5,6 +5,8 @@
  * Admin page callbacks for the Filter module.
  */
 
+use Drupal\filter\FilterFormat;
+
 /**
  * Form constructor for a form to list and reorder text formats.
  *
@@ -99,195 +101,13 @@ function theme_filter_admin_overview($variables) {
 }
 
 /**
- * Page callback: Displays the text format add/edit form.
- *
- * @param object|null $format
- *   (optional) An object representing a format, with the following properties:
- *   - format: A machine-readable name representing the ID of the text format
- *     to save. If this corresponds to an existing text format, that format
- *     will be updated; otherwise, a new format will be created.
- *   - name: The title of the text format.
- *   - cache: An integer indicating whether the text format is cacheable (1) or
- *     not (0). Defaults to 1.
- *   - status: (optional) An integer indicating whether the text format is
- *     enabled (1) or not (0). Defaults to 1.
- *   - weight: (optional) The weight of the text format, which controls its
- *     placement in text format lists. If omitted, the weight is set to 0.
- *
- * @return
- *   A form array.
- *
- * @see filter_menu()
+ * Page callback: provides the category creation form.
  */
-function filter_admin_format_page($format = NULL) {
-  if (!isset($format->name)) {
-    drupal_set_title(t('Add text format'));
-    $format = (object) array(
-      'format' => NULL,
-      'name' => '',
-    );
-  }
-  return drupal_get_form('filter_admin_format_form', $format);
+function filter_admin_format_add() {
+  $filter_format = entity_create('filter_format', array());
+  return entity_get_form($filter_format);
 }
 
-/**
- * Form constructor for the text format add/edit form.
- *
- * @param $format
- *   A format object having the properties:
- *   - format: A machine-readable name representing the ID of the text format to
- *     save. If this corresponds to an existing text format, that format will be
- *     updated; otherwise, a new format will be created.
- *   - name: The title of the text format.
- *   - cache: An integer indicating whether the text format is cacheable (1) or
- *     not (0). Defaults to 1.
- *   - status: (optional) An integer indicating whether the text format is
- *     enabled (1) or not (0). Defaults to 1.
- *   - weight: (optional) The weight of the text format, which controls its
- *     placement in text format lists. If omitted, the weight is set to 0.
- *
- * @see filter_admin_format_form_validate()
- * @see filter_admin_format_form_submit()
- * @ingroup forms
- */
-function filter_admin_format_form($form, &$form_state, $format) {
-  $is_fallback = ($format->format == filter_fallback_format());
-
-  $form['#format'] = $format;
-  $form['#tree'] = TRUE;
-  $form['#attached']['library'][] = array('filter', 'drupal.filter.admin');
-
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Name'),
-    '#default_value' => $format->name,
-    '#required' => TRUE,
-  );
-  $form['format'] = array(
-    '#type' => 'machine_name',
-    '#required' => TRUE,
-    '#default_value' => $format->format,
-    '#maxlength' => 255,
-    '#machine_name' => array(
-      'exists' => 'filter_format_exists',
-    ),
-    '#disabled' => !empty($format->format),
-  );
-
-  // Add user role access selection.
-  $form['roles'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Roles'),
-    '#options' => array_map('check_plain', user_roles()),
-    '#disabled' => $is_fallback,
-  );
-  if ($is_fallback) {
-    $form['roles']['#description'] = t('All roles for this text format must be enabled and cannot be changed.');
-  }
-  if (!empty($format->format)) {
-    // If editing an existing text format, pre-select its current permissions.
-    $form['roles']['#default_value'] = array_keys(filter_get_roles_by_format($format));
-  }
-  elseif ($admin_role = config('user.settings')->get('admin_role')) {
-    // If adding a new text format and the site has an administrative role,
-    // pre-select that role so as to grant administrators access to the new
-    // text format permission by default.
-    $form['roles']['#default_value'] = array($admin_role);
-  }
-
-  // Retrieve available filters and load all configured filters for existing
-  // text formats.
-  $filter_info = filter_get_filters();
-  $filters = !empty($format->format) ? filter_list_format($format->format) : array();
-
-  // Prepare filters for form sections.
-  foreach ($filter_info as $name => $filter) {
-    // Create an empty filter object for new/unconfigured filters.
-    if (!isset($filters[$name])) {
-      $filters[$name] = new stdClass();
-      $filters[$name]->format = $format->format;
-      $filters[$name]->module = $filter['module'];
-      $filters[$name]->name = $name;
-      $filters[$name]->status = 0;
-      $filters[$name]->weight = $filter['weight'];
-      $filters[$name]->settings = array();
-    }
-  }
-  $form['#filters'] = $filters;
-
-  // Filter status.
-  $form['filters']['status'] = array(
-    '#type' => 'item',
-    '#title' => t('Enabled filters'),
-    '#prefix' => '<div id="filters-status-wrapper">',
-    '#suffix' => '</div>',
-  );
-  foreach ($filter_info as $name => $filter) {
-    $form['filters']['status'][$name] = array(
-      '#type' => 'checkbox',
-      '#title' => $filter['title'],
-      '#default_value' => $filters[$name]->status,
-      '#parents' => array('filters', $name, 'status'),
-      '#description' => $filter['description'],
-      '#weight' => $filter['weight'],
-    );
-  }
-
-  // Filter order (tabledrag).
-  $form['filters']['order'] = array(
-    '#type' => 'item',
-    '#title' => t('Filter processing order'),
-    '#theme' => 'filter_admin_format_filter_order',
-  );
-  foreach ($filter_info as $name => $filter) {
-    $form['filters']['order'][$name]['filter'] = array(
-      '#markup' => $filter['title'],
-    );
-    $form['filters']['order'][$name]['weight'] = array(
-      '#type' => 'weight',
-      '#title' => t('Weight for @title', array('@title' => $filter['title'])),
-      '#title_display' => 'invisible',
-      '#delta' => 50,
-      '#default_value' => $filters[$name]->weight,
-      '#parents' => array('filters', $name, 'weight'),
-    );
-    $form['filters']['order'][$name]['#weight'] = $filters[$name]->weight;
-  }
-
-  // Filter settings.
-  $form['filter_settings_title'] = array(
-    '#type' => 'item',
-    '#title' => t('Filter settings'),
-  );
-  $form['filter_settings'] = array(
-    '#type' => 'vertical_tabs',
-  );
-
-  foreach ($filter_info as $name => $filter) {
-    if (isset($filter['settings callback'])) {
-      $function = $filter['settings callback'];
-      // Pass along stored filter settings and default settings, but also the
-      // format object and all filters to allow for complex implementations.
-      $defaults = (isset($filter['default settings']) ? $filter['default settings'] : array());
-      $settings_form = $function($form, $form_state, $filters[$name], $format, $defaults, $filters);
-      if (!empty($settings_form)) {
-        $form['filters']['settings'][$name] = array(
-          '#type' => 'fieldset',
-          '#title' => $filter['title'],
-          '#parents' => array('filters', $name, 'settings'),
-          '#weight' => $filter['weight'],
-          '#group' => 'filter_settings',
-        );
-        $form['filters']['settings'][$name] += $settings_form;
-      }
-    }
-  }
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
-
-  return $form;
-}
 
 /**
  * Returns HTML for a text format's filter order form.
diff --git a/core/modules/filter/filter.info b/core/modules/filter/filter.info
index 03ed179..e399611 100644
--- a/core/modules/filter/filter.info
+++ b/core/modules/filter/filter.info
@@ -5,3 +5,4 @@ version = VERSION
 core = 8.x
 required = TRUE
 configure = admin/config/content/formats
+dependencies[] = config
diff --git a/core/modules/filter/filter.install b/core/modules/filter/filter.install
index 9237ad1..fb357c5 100644
--- a/core/modules/filter/filter.install
+++ b/core/modules/filter/filter.install
@@ -5,105 +5,12 @@
  * Install, update, and uninstall functions for the Filter module.
  */
 
+use Drupal\filter\FilterFormat;
+
 /**
  * Implements hook_schema().
  */
 function filter_schema() {
-  $schema['filter'] = array(
-    'description' => 'Table that maps filters (HTML corrector) to text formats (Filtered HTML).',
-    'fields' => array(
-      'format' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'description' => 'Foreign key: The {filter_format}.format to which this filter is assigned.',
-      ),
-      'module' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The origin module of the filter.',
-      ),
-      'name' => array(
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Name of the filter being referenced.',
-      ),
-      'weight' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Weight of filter within format.',
-      ),
-      'status' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Filter enabled status. (1 = enabled, 0 = disabled)',
-      ),
-      'settings' => array(
-        'type' => 'blob',
-        'not null' => FALSE,
-        'size' => 'big',
-        'serialize' => TRUE,
-        'description' => 'A serialized array of name value pairs that store the filter settings for the specific format.',
-      ),
-    ),
-    'primary key' => array('format', 'name'),
-    'indexes' => array(
-      'list' => array('weight', 'module', 'name'),
-    ),
-  );
-  $schema['filter_format'] = array(
-    'description' => 'Stores text formats: custom groupings of filters, such as Filtered HTML.',
-    'fields' => array(
-      'format' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique machine name of the format.',
-      ),
-      'name' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Name of the text format (Filtered HTML).',
-        'translatable' => TRUE,
-      ),
-      'cache' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-        'description' => 'Flag to indicate whether format is cacheable. (1 = cacheable, 0 = not cacheable)',
-      ),
-      'status' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 1,
-        'size' => 'tiny',
-        'description' => 'The status of the text format. (1 = enabled, 0 = disabled)',
-      ),
-      'weight' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Weight of text format to use when listing.',
-      ),
-    ),
-    'primary key' => array('format'),
-    'unique keys' => array(
-      'name' => array('name'),
-    ),
-    'indexes' => array(
-      'status_weight' => array('status', 'weight'),
-    ),
-  );
 
   $schema['cache_filter'] = drupal_get_schema_unprocessed('system', 'cache');
   $schema['cache_filter']['description'] = 'Cache table for the Filter module to store already filtered pieces of text, identified by text format and hash of the text.';
@@ -119,30 +26,28 @@ function filter_install() {
   // users have access to, so add it here. We initialize it as a simple, safe
   // plain text format with very basic formatting, but it can be modified by
   // installation profiles to have other properties.
-  $plain_text_format = array(
-    'format' => 'plain_text',
-    'name' => 'Plain text',
-    'weight' => 10,
-    'filters' => array(
-      // Escape all HTML.
-      'filter_html_escape' => array(
-        'weight' => 0,
-        'status' => 1,
-      ),
-      // URL filter.
-      'filter_url' => array(
-        'weight' => 1,
-        'status' => 1,
-      ),
-      // Line break filter.
-      'filter_autop' => array(
-        'weight' => 2,
-        'status' => 1,
-      ),
+  $plain_text_format = new FilterFormat();
+  $plain_text_format->format = 'plain_text';
+  $plain_text_format->name = 'Plain Text';
+  $plain_text_format->weight = 10;
+  $plain_text_format->filters = array(
+    // Escape all HTML.
+    'filter_html_escape' => array(
+      'weight' => 0,
+      'status' => 1,
+    ),
+    // URL filter.
+    'filter_url' => array(
+      'weight' => 1,
+      'status' => 1,
+    ),
+    // Line break filter.
+    'filter_autop' => array(
+      'weight' => 2,
+      'status' => 1,
     ),
   );
-  $plain_text_format = (object) $plain_text_format;
-  filter_format_save($plain_text_format);
+  $plain_text_format->save();
 
   // Set the fallback format to plain text.
   variable_set('filter_fallback_format', $plain_text_format->format);
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 6c54fae..ee4f86e 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -5,6 +5,7 @@
  * Framework for handling the filtering of content.
  */
 use Drupal\Core\Template\Attribute;
+use Drupal\filter\FilterFormat;
 
 /**
  * Implements hook_cache_flush().
@@ -123,7 +124,7 @@ function filter_menu() {
   );
   $items['admin/config/content/formats/add'] = array(
     'title' => 'Add text format',
-    'page callback' => 'filter_admin_format_page',
+    'page callback' => 'filter_admin_format_add',
     'access arguments' => array('administer filters'),
     'type' => MENU_LOCAL_ACTION,
     'weight' => 1,
@@ -132,7 +133,7 @@ function filter_menu() {
   $items['admin/config/content/formats/%filter_format'] = array(
     'title callback' => 'filter_admin_format_title',
     'title arguments' => array(4),
-    'page callback' => 'filter_admin_format_page',
+    'page callback' => 'entity_get_form',
     'page arguments' => array(4),
     'access arguments' => array('administer filters'),
     'file' => 'filter.admin.inc',
@@ -149,6 +150,76 @@ function filter_menu() {
 }
 
 /**
+ * Implements MODULE_config_import_create().
+ */
+function filter_config_import_create($name, $new_config, $old_config) {
+  if (strpos($name, 'filter.filter_format.') !== 0) {
+    return FALSE;
+  }
+
+  $filter_format = entity_create('filter_format', $new_config->get());
+  $filter_format->save();
+  return TRUE;
+}
+
+/**
+ * Implements MODULE_config_import_change().
+ */
+function filter_config_import_change($name, $new_config, $old_config) {
+  if (strpos($name, 'filter.filter_format.') !== 0) {
+    return FALSE;
+  }
+
+  list(, , $id) = explode('.', $name);
+  $filter_format = entity_load('filter_format', $id);
+
+  $filter_format->original = clone $filter_format;
+  foreach ($old_config->get() as $property => $value) {
+    $filter_format->original->$property = $value;
+  }
+
+  foreach ($new_config->get() as $property => $value) {
+    $filter_format->$property = $value;
+  }
+
+  $filter_format->save();
+  return TRUE;
+}
+
+/**
+ * Implements MODULE_config_import_delete().
+ */
+function filter_config_import_delete($name, $new_config, $old_config) {
+  if (strpos($name, 'filter.filter_format.') !== 0) {
+    return FALSE;
+  }
+
+  list(, , $id) = explode('.', $name);
+  entity_delete_multiple('filter_format', array($id));
+  return TRUE;
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function filter_entity_info() {
+  $types['filter_format'] = array(
+    'label' => 'Filter Format',
+    'entity class' => 'Drupal\filter\FilterFormat',
+    'controller class' => 'Drupal\config\ConfigStorageController',
+    'form controller class' => array(
+      'default' => 'Drupal\filter\FilterFormatFormController',
+    ),
+    'config prefix' => 'filter.filter_format',
+    'entity keys' => array(
+      'format' => 'format',
+      'uuid' => 'uuid',
+    ),
+  );
+  return $types;
+}
+
+/**
  * Access callback: Checks access for disabling text formats.
  *
  * @param $format
@@ -221,17 +292,6 @@ function filter_format_save($format) {
     $format->weight = 0;
   }
 
-  // Insert or update the text format.
-  $return = db_merge('filter_format')
-    ->key(array('format' => $format->format))
-    ->fields(array(
-      'name' => $format->name,
-      'cache' => (int) $format->cache,
-      'status' => (int) $format->status,
-      'weight' => (int) $format->weight,
-    ))
-    ->execute();
-
   // Programmatic saves may not contain any filters.
   if (!isset($format->filters)) {
     $format->filters = array();
@@ -257,22 +317,10 @@ function filter_format_save($format) {
     else {
       $format->filters[$name]['settings'] = isset($filter['default settings']) ? $filter['default settings'] : array();
     }
-
-    $fields = array();
-    $fields['weight'] = $format->filters[$name]['weight'];
-    $fields['status'] = $format->filters[$name]['status'];
-    $fields['module'] = $format->filters[$name]['module'];
-    $fields['settings'] = serialize($format->filters[$name]['settings']);
-
-    db_merge('filter')
-      ->key(array(
-        'format' => $format->format,
-        'name' => $name,
-      ))
-      ->fields($fields)
-      ->execute();
   }
 
+  $return = $format->save();
+
   if ($return == SAVED_NEW) {
     module_invoke_all('filter_format_insert', $format);
   }
@@ -305,10 +353,8 @@ function filter_format_save($format) {
  *   The text format object to be disabled.
  */
 function filter_format_disable($format) {
-  db_update('filter_format')
-    ->fields(array('status' => 0))
-    ->condition('format', $format->format)
-    ->execute();
+  $format->status = 0;
+  $format->save();
 
   // Allow modules to react on text format deletion.
   module_invoke_all('filter_format_disable', $format);
@@ -332,7 +378,8 @@ function filter_format_disable($format) {
  * @see filter_format_load()
  */
 function filter_format_exists($format_id) {
-  return (bool) db_query_range('SELECT 1 FROM {filter_format} WHERE format = :format', 0, 1, array(':format' => $format_id))->fetchField();
+  $formats = entity_load_multiple('filter_formats');
+  return !empty($formats[$format_id]);
 }
 
 /**
@@ -431,13 +478,8 @@ function filter_formats($account = NULL) {
       $formats['all'] = $cache->data;
     }
     else {
-      $formats['all'] = db_select('filter_format', 'ff')
-        ->addTag('translatable')
-        ->fields('ff')
-        ->condition('status', 1)
-        ->orderBy('weight')
-        ->execute()
-        ->fetchAllAssoc('format');
+      $filter_formats = entity_load_multiple_by_properties('filter_format', array('status' => 1));
+      uasort($filter_formats, 'Drupal\config\ConfigEntityBase::sort');
 
       cache()->set("filter_formats:{$language_interface->langcode}", $formats['all']);
     }
@@ -703,9 +745,12 @@ function filter_list_format($format_id) {
       $filters['all'] = $cache->data;
     }
     else {
-      $result = db_query('SELECT * FROM {filter} ORDER BY weight, module, name');
-      foreach ($result as $record) {
-        $filters['all'][$record->format][$record->name] = $record;
+      $filter_formats = filter_formats();
+      foreach ($filter_formats as $filter_format) {
+        foreach ($filter_format->filers as $filter) {
+          $filters['all'][$filter_format->format][$filter->name] = $filter;
+        }
+
       }
       cache()->set('filter_list_format', $filters['all']);
     }
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatFormController.php b/core/modules/filter/lib/Drupal/filter/FilterFormatFormController.php
new file mode 100644
index 0000000..b43a27c
--- /dev/null
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatFormController.php
@@ -0,0 +1,172 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\filter_format\FilterFormatFormController.
+ */
+
+namespace Drupal\filter;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Base form controller for category edit forms.
+ */
+class FilterFormatFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  function form(array $form, array &$form_state, FilterFormat $format) {
+    $is_fallback = ($format->format == filter_fallback_format());
+
+    $form['#format'] = $format;
+    $form['#tree'] = TRUE;
+    $form['#attached']['library'][] = array('filter', 'drupal.filter.admin');
+
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#default_value' => $format->name,
+      '#required' => TRUE,
+    );
+    $form['format'] = array(
+      '#type' => 'machine_name',
+      '#required' => TRUE,
+      '#default_value' => $format->format,
+      '#maxlength' => 255,
+      '#machine_name' => array(
+        'exists' => 'filter_format_exists',
+      ),
+      '#disabled' => !empty($format->format),
+    );
+
+    // Add user role access selection.
+    $form['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Roles'),
+      '#options' => array_map('check_plain', user_roles()),
+      '#disabled' => $is_fallback,
+    );
+    if ($is_fallback) {
+      $form['roles']['#description'] = t('All roles for this text format must be enabled and cannot be changed.');
+    }
+    if (!empty($format->format)) {
+      // If editing an existing text format, pre-select its current permissions.
+      $form['roles']['#default_value'] = array_keys(filter_get_roles_by_format($format));
+    }
+    elseif ($admin_role = config('user.settings')->get('admin_role')) {
+      // If adding a new text format and the site has an administrative role,
+      // pre-select that role so as to grant administrators access to the new
+      // text format permission by default.
+      $form['roles']['#default_value'] = array($admin_role);
+    }
+
+    // Retrieve available filters and load all configured filters for existing
+    // text formats.
+    $filter_info = filter_get_filters();
+    $filters = !empty($format->format) ? filter_list_format($format->format) : array();
+
+    // Prepare filters for form sections.
+    foreach ($filter_info as $name => $filter) {
+      // Create an empty filter object for new/unconfigured filters.
+      if (!isset($filters[$name])) {
+        $filters[$name] = new stdClass();
+        $filters[$name]->format = $format->format;
+        $filters[$name]->module = $filter['module'];
+        $filters[$name]->name = $name;
+        $filters[$name]->status = 0;
+        $filters[$name]->weight = $filter['weight'];
+        $filters[$name]->settings = array();
+      }
+    }
+    $form['#filters'] = $filters;
+
+    // Filter status.
+    $form['filters']['status'] = array(
+      '#type' => 'item',
+      '#title' => t('Enabled filters'),
+      '#prefix' => '<div id="filters-status-wrapper">',
+      '#suffix' => '</div>',
+    );
+    foreach ($filter_info as $name => $filter) {
+      $form['filters']['status'][$name] = array(
+        '#type' => 'checkbox',
+        '#title' => $filter['title'],
+        '#default_value' => $filters[$name]->status,
+        '#parents' => array('filters', $name, 'status'),
+        '#description' => $filter['description'],
+        '#weight' => $filter['weight'],
+      );
+    }
+
+    // Filter order (tabledrag).
+    $form['filters']['order'] = array(
+      '#type' => 'item',
+      '#title' => t('Filter processing order'),
+      '#theme' => 'filter_admin_format_filter_order',
+    );
+    foreach ($filter_info as $name => $filter) {
+      $form['filters']['order'][$name]['filter'] = array(
+        '#markup' => $filter['title'],
+      );
+      $form['filters']['order'][$name]['weight'] = array(
+        '#type' => 'weight',
+        '#title' => t('Weight for @title', array('@title' => $filter['title'])),
+        '#title_display' => 'invisible',
+        '#delta' => 50,
+        '#default_value' => $filters[$name]->weight,
+        '#parents' => array('filters', $name, 'weight'),
+      );
+      $form['filters']['order'][$name]['#weight'] = $filters[$name]->weight;
+    }
+
+    // Filter settings.
+    $form['filter_settings_title'] = array(
+      '#type' => 'item',
+      '#title' => t('Filter settings'),
+    );
+    $form['filter_settings'] = array(
+      '#type' => 'vertical_tabs',
+    );
+
+    foreach ($filter_info as $name => $filter) {
+      if (isset($filter['settings callback'])) {
+        $function = $filter['settings callback'];
+        // Pass along stored filter settings and default settings, but also the
+        // format object and all filters to allow for complex implementations.
+        $defaults = (isset($filter['default settings']) ? $filter['default settings'] : array());
+        $settings_form = $function($form, $form_state, $filters[$name], $format, $defaults, $filters);
+        if (!empty($settings_form)) {
+          $form['filters']['settings'][$name] = array(
+            '#type' => 'fieldset',
+            '#title' => $filter['title'],
+            '#parents' => array('filters', $name, 'settings'),
+            '#weight' => $filter['weight'],
+            '#group' => 'filter_settings',
+          );
+          $form['filters']['settings'][$name] += $settings_form;
+        }
+      }
+    }
+
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
+
+    return parent::form($form, $form_state, $format);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $filter_format = $this->getEntity($form_state);
+    $filter_format->save();
+
+    drupal_set_message(t('Filter Format %label has been saved.', array('%label' => $filter_format->label())));
+    watchdog('filter_format', 'Filter Format %label has been saved.', array('%label' => $filter_format->label()), WATCHDOG_NOTICE, l(t('Edit'), 'admin/structure/filter_format/manage/' . $filter_format->id()));
+
+    $form_state['redirect'] = 'admin/config/content/formats';
+  }
+}
diff --git a/core/modules/filter/lib/Drupal/filter/TextFormat.php b/core/modules/filter/lib/Drupal/filter/TextFormat.php
new file mode 100644
index 0000000..d412beb
--- /dev/null
+++ b/core/modules/filter/lib/Drupal/filter/TextFormat.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\filter\FilterFormat.
+ */
+
+namespace Drupal\filter;
+
+use Drupal\config\ConfigEntityBase;
+
+/**
+ * Defines the Filter Format entity.
+ */
+class FilterFormat extends ConfigEntityBase {
+
+  /**
+   * Unique machine name of the format.
+   *
+   * @var string
+   */
+  public $format;
+
+  /**
+   * Name of the text format (Filtered HTML).
+   *
+   * @var string
+   */
+  public $name;
+
+  /**
+   * Flag to indicate whether format is cacheable. (1 = cacheable, 0 = not
+   * cacheable).
+   *
+   * @var int
+   */
+  public $cache = 0;
+
+  /**
+   * The status of the text format. (1 = enabled, 0 = disabled)
+   *
+   * @var int
+   */
+  public $status = 1;
+
+  /**
+   * Weight of text format to use when listing.
+   *
+   * @var int
+   */
+  public $weight = 0;
+
+  /**
+   * An array of of name value of the enabled filters for this text format.
+   *
+   * Each element of this array must contain at least the following values:
+   *   - weight: Weight of filter within format.
+   *   - settings: An array of name value pairs that store the filter settings
+   *     for the specific format.
+   *
+   * @var array
+   */
+  public $filters = array();
+
+}
