diff --git a/core/modules/editor/editor.api.php b/core/modules/editor/editor.api.php
new file mode 100644
index 0000000..c4ca2cb
--- /dev/null
+++ b/core/modules/editor/editor.api.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Documentation for Text Editor API.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Perform alterations on text editor definitions.
+ *
+ * @param array $editors
+ *   An array of information on text editors, as collected by the annotation
+ *   discovery mechanism.
+ *
+ * @see \Drupal\editor\Plugin\EditorBase
+ */
+function hook_editor_info_alter(array &$editors) {
+  $editors['some_other_editor']['title'] = t('A different name');
+  $editors['some_other_editor']['library']['module'] = 'myeditoroverride';
+}
+
+/**
+ * Modifies JavaScript settings that are added for text editors.
+ *
+ * @param array $settings
+ *   All the settings that will be added to the page via drupal_add_js() for
+ *   the text formats to which a user has access.
+ * @param array $formats
+ *   The list of format objects for which settings are being added.
+ */
+function hook_editor_js_settings_alter(array &$settings, array $formats) {
+  if (isset($formats['filtered_html'])) {
+    $settings['filtered_html']['editor'][] = 'MyDifferentEditor';
+    $settings['filtered_html']['editorSettings']['buttons'] = array('strong', 'italic', 'underline');
+  }
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/core/modules/editor/editor.info b/core/modules/editor/editor.info
new file mode 100644
index 0000000..15aab7d
--- /dev/null
+++ b/core/modules/editor/editor.info
@@ -0,0 +1,7 @@
+name = Text Editor
+description = "Provides a framework for associating text formats with text editor libraries such as WYSIWYGs or toolbars."
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = filter
+configure = admin/config/content/formats
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
new file mode 100644
index 0000000..b115693
--- /dev/null
+++ b/core/modules/editor/editor.module
@@ -0,0 +1,287 @@
+<?php
+
+/**
+ * @file
+ * Adds bindings for client-side "text editors" to text formats.
+ */
+
+use Drupal\file\Plugin\Core\Entity\File;
+use Drupal\editor\Plugin\Core\Entity\Editor;
+use Drupal\Component\Utility\NestedArray;
+
+/**
+ * Implements hook_help().
+ */
+function editor_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#editor':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Text Editor module provides a framework to extend the user interface on text fields that allow HTML input. Without Text Editor module, fields accept only text where formatting must be typed manually, such as entering a <code>&lt;strong&gt;</code> tag to make text bold or an <code>&lt;em&gt;</code> tag to italicize text. The Text Editor module allows these fields to be enhanced with rich text editors (WYSIWYGs) or toolbars, which make entering and formatting content easier. For more information, see the online handbook entry for <a href="@editor">Editor module</a>.', array('@editor' => 'http://drupal.org/documentation/modules/editor/')) . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Enabling or configuring a text editor') . '</dt>';
+      $output .= '<dd>' . t('The Text Editor module does not have its own configuration page. Instead it enhances existing configuration pages with additional options. Text editors are attached to individual text formats, which can be configured on the <a href="@formats">Text formats page</a>. Each text format may be associated with a single text editor. When entering content with that text format, the associated text editor will automatically be enabled.', array('@formats' => url('admin/config/content/formats'))) . '</dd>';
+      $output .= '<dt>' . t('Allowing a user to choose a text editor') . '</dt>';
+      $output .= '<dd>' . t('Because text editor configurations are bound to a text format, users with access to more than one text format may switch between available text editors by changing the text format for a field. For more information about text formats, see the <a href="@filter">Filter module help page</a>, which describes text formats in more detail.', array('@filter' => url('admin/help/filter'))) . '</dd>';
+      // @todo: Mention the availability of the built-in core WYSIWYG (CKEditor)
+      // when it becomes available. See http://drupal.org/node/1878344.
+      $output .= '<dt>' . t('Installing additional text editor libraries') . '</dt>';
+      $output .= '<dd>' . t('The Text Editor module does not provide any text editor libraries itself. Most installations of Drupal include a module that provides a text editor library which may be enabled on the <a href="@modules">Modules page</a>. Additional modules that provide text editor libraries may be <a href="@download">downloaded from Drupal.org</a>.', array('@modules' => url('admin/modules'), '@download' => 'http://drupal.org/search/site/wysiwyg%20module')) . '</dd>';
+      $output .= '</dl>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_menu_alter().
+ *
+ * Rewrites the menu entries for filter module that relate to the configuration
+ * of text editors.
+ */
+function editor_menu_alter(&$items) {
+  $items['admin/config/content/formats']['title'] = 'Text formats and editors';
+  $items['admin/config/content/formats']['description'] = 'Configure the processing of text, including toolbars or WYSIWYG editors used on input, and allowed HTML tags and automatic formatting used on output.';
+}
+
+/**
+ * Implements hook_element_info().
+ *
+ * Extends the functionality of text_format elements (provided by Filter
+ * module), so that selecting a text format notifies a client-side text editor
+ * when it should be enabled or disabled.
+ *
+ * @see filter_element_info()
+ */
+function editor_element_info() {
+  $type['text_format'] = array(
+    '#process' => array('editor_process_format'),
+  );
+  return $type;
+}
+
+/**
+ * Implements hook_library_info().
+ */
+function editor_library_info() {
+  $path = drupal_get_path('module', 'editor');
+  $libraries['drupal.editor'] = array(
+    'title' => 'Editor',
+    'version' => VERSION,
+    'js' => array(
+      $path . '/js/editor.js' => array('group' => JS_LIBRARY),
+    ),
+    'dependencies' => array(
+      array('system', 'jquery'),
+      array('system', 'drupal'),
+      array('system', 'drupalSettings'),
+      array('system', 'jquery.once'),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function editor_form_filter_admin_overview_alter(&$form, $form_state) {
+  // @todo Cleanup column injection: http://drupal.org/node/1876718
+  // Splice in the column for "Associated editor" into the header.
+  $position = array_search('name', $form['formats']['#header']) + 1;
+  $start = array_splice($form['formats']['#header'], 0, $position, array('editor' => t('Associated editor')));
+  $form['formats']['#header'] = array_merge($start, $form['formats']['#header']);
+
+  // Then splice in the name of each text editor for each text format.
+  $editors = drupal_container()->get('plugin.manager.editor')->getDefinitions();
+  foreach (element_children($form['formats']) as $format_id) {
+    $editor = editor_load($format_id);
+    $editor_name = ($editor && isset($editors[$editor->editor])) ? $editors[$editor->editor]['title'] : drupal_placeholder(t('None'));
+    $editor_column['editor'] = array(
+      '#type' => 'markup',
+      '#markup' => $editor_name,
+    );
+    $position = array_search('name', array_keys($form['formats'][$format_id])) + 1;
+    $start = array_splice($form['formats'][$format_id], 0, $position, $editor_column);
+    $form['formats'][$format_id] = array_merge($start, $form['formats'][$format_id]);
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function editor_form_filter_admin_format_form_alter(&$form, &$form_state) {
+  $format = $form['#format'];
+  $editor = editor_load($format->format);
+  $manager = drupal_container()->get('plugin.manager.editor');
+
+  // Check if we're switching to a different text editor and load that form.
+  if (isset($form_state['values']['editor'])) {
+    if ($form_state['values']['editor'] === '') {
+      $editor = FALSE;
+    }
+    elseif (empty($editor) || $form_state['values']['editor'] !== $editor->editor) {
+      $editor = entity_create('editor', array(
+        'name' => $format->name,
+        'format' => $format->format,
+        'editor' => $form_state['values']['editor'],
+      ));
+    }
+  }
+
+  // Associate a text editor with this text format.
+  $editor_options = $manager->listOptions();
+  $form['editor'] = array(
+    '#type' => 'select',
+    '#title' => t('Editor'),
+    '#options' => $editor_options,
+    '#empty_option' => t('None'),
+    '#default_value' => $editor ? $editor->editor : '',
+    // Position the editor selection before the filter settings (weight of 0),
+    // but after the filter label and name (weight of -20).
+    '#weight' => -9,
+    '#ajax' => array(
+      'callback' => 'editor_form_filter_admin_form_ajax',
+      'wrapper' => 'editor-settings-wrapper',
+    ),
+  );
+
+  // If there aren't any options (other than "None") disable the select list.
+  if (empty($editor_options)) {
+    $form['editor']['#disabled'] = TRUE;
+    $form['editor']['#description'] = t('This option is disabled because no modules that provide an editor are currently enabled.');
+  }
+
+  $form['editor_settings'] = array(
+    '#tree' => TRUE,
+    '#weight' => -8,
+    '#type' => 'group',
+    '#prefix' => '<div id="editor-settings-wrapper">',
+    '#suffix' => '</div>',
+  );
+
+  // Add validation per-editor validation and submit handlers.
+  if ($editor) {
+    $plugin = $manager->createInstance($editor->editor);
+    $form['editor_settings'] = array_merge($form['editor_settings'], $plugin->settingsForm($form, $form_state, $editor));
+    // Place validation first since editor validation errors should appear above
+    // individual filter validation errors.
+    array_unshift($form['#validate'], array($plugin, 'settingsFormValidate'));
+    $form['#submit'][] = array($plugin, 'settingsFormSubmit');
+  }
+
+  $form['#submit'][] = 'editor_form_filter_admin_format_submit';
+}
+
+/**
+ * AJAX submit handler for filter_admin_format_form().
+ */
+function editor_form_filter_admin_form_ajax($form, &$form_state) {
+  return $form['editor_settings'];
+}
+
+/**
+ * Additional submit handler for filter_admin_format_form().
+ */
+function editor_form_filter_admin_format_submit($form, &$form_state) {
+  $format = $form['#format'];
+  $editor = editor_load($format->format);
+
+  // Delete the existing editor if disabling or switching between editors.
+  if ($editor && $editor->editor != $form_state['values']['editor']) {
+    $editor->delete();
+    $editor = FALSE;
+  }
+
+  // Create a new editor or update the existing editor.
+  if ($form_state['values']['editor']) {
+    if (!$editor) {
+      $editor = entity_create('editor', array(
+        'name' => $format->name,
+        'format' => $format->format,
+        'editor' => $form_state['values']['editor'],
+      ));
+    }
+    if (isset($form_state['values']['editor_settings'])) {
+      $editor->settings = $form_state['values']['editor_settings'];
+    }
+    $editor->save();
+  }
+}
+
+/**
+ * Loads an individual configured text editor based on format ID.
+ *
+ * @return \Drupal\editor\Plugin\Core\Entity\Editor|FALSE
+ *   A text editor object, or FALSE.
+ */
+function editor_load($format_id) {
+  // Load all the editors at once here, assuming that either no editors or more
+  // than one editor will be needed on a page (such as having multiple text
+  // formats for administrators). Loading a small number of editors all at once
+  // is more efficient than loading multiple editors individually.
+  $editors = entity_load_multiple('editor');
+  return isset($editors[$format_id]) ? $editors[$format_id] : FALSE;
+}
+
+/**
+ * Additional #process callback for 'text_format' elements.
+ */
+function editor_process_format($element) {
+  global $user;
+
+  $formats = filter_formats($user);
+
+  if (!isset($element['#attached'])) {
+    $element['#attached'] = array();
+  }
+  $element['#attached'] = NestedArray::mergeDeep($element['#attached'], editor_get_attachments($formats));
+
+  return $element;
+}
+
+/**
+ * Retrieves text editor libraries and JavaScript settings.
+ *
+ * @param array $formats
+ *   An array of formats as returned by filter_formats().
+ * @return array
+ *   An array of library attachments, for use with #attached.
+ *
+ * @see drupal_process_attached()
+ */
+function editor_get_attachments($formats) {
+  $attachments = array();
+
+  $manager = drupal_container()->get('plugin.manager.editor');
+  $definitions = $manager->getDefinitions();
+
+  $settings = array();
+  foreach ($formats as $format_id => $format_info) {
+    $editor = editor_load($format_id);
+    if (!$editor) {
+      continue;
+    }
+
+    // Library.
+    $library = $definitions[$editor->editor]['library'];
+    $attachments['library'][] = array($library['module'], $library['name']);
+
+    // JavaScript settings.
+    $plugin = $manager->createInstance($editor->editor);
+    $settings[$format_id] = array(
+      'editor' => $editor->editor,
+      'editorSettings' => $plugin->generateJSSettings($editor),
+    );
+  }
+
+  // We have all JavaScript settings, allow other modules to alter them.
+  drupal_alter('editor_js_settings', $settings, $formats);
+
+  $attachments['js'][] = array(
+    'type' => 'setting',
+    'data' => array('editor' => array('formats' => $settings)),
+  );
+
+  return $attachments;
+}
diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js
new file mode 100644
index 0000000..bb651c3
--- /dev/null
+++ b/core/modules/editor/js/editor.js
@@ -0,0 +1,80 @@
+/**
+ * @file
+ * Attaches behavior for the Editor module.
+ */
+
+(function ($, Drupal, drupalSettings) {
+
+"use strict";
+
+/**
+ * Initialize an empty object for editors to place their attachment code.
+ */
+Drupal.editors = {};
+
+/**
+ * Enables editors on text_format elements.
+ */
+Drupal.behaviors.editors = {
+  attach: function (context, settings) {
+    // If there are no editor settings, there are no editors to enable.
+    if (!settings.editor) {
+      return;
+    }
+
+    var $context = $(context);
+    $context.find('.filter-list:input').once('editors', function () {
+      var $this = $(this);
+      var activeEditor = $this.val();
+      var field = $this.closest('.text-format-wrapper').find('textarea').get(-1);
+
+      // Directly attach this editor, if the text format is enabled or there is
+      // only one text format at all.
+      if ($this.is(':input')) {
+        if (drupalSettings.editor.formats[activeEditor]) {
+          Drupal.editorAttach(field, drupalSettings.editor.formats[activeEditor]);
+        }
+      }
+      // Attach onChange handlers to text format selector elements.
+      if ($this.is('select')) {
+        $this.on('change.editorAttach', function () {
+          // Prevent double-binding if the change event is triggered manually.
+          if ($this.val() === activeEditor) {
+            return;
+          }
+
+          // Detach the current editor (if any) and attach a new editor.
+          if (drupalSettings.editor.formats[activeEditor]) {
+            Drupal.editorDetach(field, drupalSettings.editor.formats[activeEditor]);
+          }
+          activeEditor = $this.val();
+          if (drupalSettings.editor.formats[activeEditor]) {
+            Drupal.editorAttach(field, drupalSettings.editor.formats[activeEditor]);
+          }
+        });
+      }
+      // Detach any editor when the containing form is submitted.
+      $this.parents('form').submit(function (event) {
+        // Do not detach if the event was canceled.
+        if (event.isDefaultPrevented()) {
+          return;
+        }
+        Drupal.editorDetach(field, drupalSettings.editor.formats[activeEditor]);
+      });
+    });
+  }
+};
+
+Drupal.editorAttach = function (field, format) {
+  if (format.editor) {
+    Drupal.editors[format.editor].attach(field, format);
+  }
+};
+
+Drupal.editorDetach = function (field, format) {
+  if (format.editor) {
+    Drupal.editors[format.editor].detach(field, format);
+  }
+};
+
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/editor/lib/Drupal/editor/EditorBundle.php b/core/modules/editor/lib/Drupal/editor/EditorBundle.php
new file mode 100644
index 0000000..1e4b86a
--- /dev/null
+++ b/core/modules/editor/lib/Drupal/editor/EditorBundle.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\editor\EditorBundle.
+ */
+
+namespace Drupal\editor;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Editor dependency injection container.
+ */
+class EditorBundle extends Bundle {
+
+  /**
+   * Overrides Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    // Register the plugin manager for our plugin type with the dependency
+    // injection container.
+    $container->register('plugin.manager.editor', 'Drupal\editor\Plugin\EditorManager');
+  }
+
+}
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php b/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php
new file mode 100644
index 0000000..0ed6c3a
--- /dev/null
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/Core/Entity/Editor.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\editor\Plugin\Core\Entity\Editor.
+ */
+
+namespace Drupal\editor\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the configured text editor entity.
+ *
+ * @Plugin(
+ *   id = "editor",
+ *   label = @Translation("Editor"),
+ *   module = "editor",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   config_prefix = "editor.editor",
+ *   entity_keys = {
+ *     "id" = "format",
+ *     "label" = "name",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class Editor extends ConfigEntityBase {
+
+  /**
+   * The machine name of the text format to which this text editor is bound.
+   *
+   * @var string
+   */
+  public $format;
+
+  /**
+   * The label of the text format to which this text editor is bound.
+   *
+   * @var string
+   */
+  public $name;
+
+  /**
+   * The name of the text editor library.
+   *
+   * @var string
+   */
+  public $editor;
+
+  /**
+   * The array of settings for this text editor.
+   *
+   * @var array
+   */
+  public $settings = array();
+
+  /**
+   * Overrides Drupal\Core\Entity\Entity::id().
+   */
+  public function id() {
+    return $this->format;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\Entity::__construct()
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+
+    // Initialize settings to the defaults, merging any passed in settings.
+    $manager = drupal_container()->get('plugin.manager.editor');
+    $plugin = $manager->createInstance($this->editor);
+    $this->settings = array_merge($plugin->defaultSettings(), $this->settings);
+  }
+
+}
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/EditorBase.php b/core/modules/editor/lib/Drupal/editor/Plugin/EditorBase.php
new file mode 100644
index 0000000..fbba638
--- /dev/null
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/EditorBase.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Definition of \Drupal\editor\Plugin\EditorBase.
+ */
+
+namespace Drupal\editor\Plugin;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\editor\Plugin\Core\Entity\Editor;
+use Drupal\editor\Plugin\EditorInterface;
+
+/**
+ * Defines a base class from which other modules providing editors may extend.
+ *
+ * This class provides default implementations of the EditorInterface so that
+ * classes extending this one do not need to implement every method.
+ *
+ * Plugins extending this class need to define a plugin definition array through
+ * annotation. These definition arrays may be altered through
+ * hook_editor_info_alter(). The definition includes the following keys:
+ *
+ * - id: The unique, system-wide identifier of the text editor. Typically named
+ *     the same as the editor library.
+ * - title: The human-readable name of the text editor, translated.
+ * - library: A nested array containing key-value pairs for adding library to
+ *     the page, as done through drupal_add_library. This array should have two
+ *     keys:
+ *   - module: The name of the module providing the editor library.
+ *   - name: The name of the library to be added, as defined in hook_library().
+ *
+ * A complete sample plugin definition should be defined as in this example:
+ *
+ * @code
+ * @Plugin(
+ *   id = "myeditor",
+ *   title = @Translation("My Editor"),
+ *   library = {
+ *     "module" = "myeditor",
+ *     "name" = "drupal.myeditor"
+ *   }
+ * )
+ * @endcode
+ */
+abstract class EditorBase extends PluginBase implements EditorInterface {
+
+  /**
+   * Implements \Drupal\editor\Plugin\EditorInterface::defaultSettings().
+   */
+  public function defaultSettings() {
+    return array();
+  }
+
+  /**
+   * Implements \Drupal\editor\Plugin\EditorInterface::settingsForm().
+   */
+  public function settingsForm(array &$form, array &$form_state, Editor $editor) {
+    return array();
+  }
+
+  /**
+   * Implements \Drupal\editor\Plugin\EditorInterface::settingsFormValidate().
+   */
+  public function settingsFormValidate(array $form, array &$form_state) {
+    // Use form_set_error() to declare any validation errors.
+  }
+
+  /**
+   * Implements \Drupal\editor\Plugin\EditorInterface::settingsFormSubmit().
+   */
+  public function settingsFormSubmit(array $form, array &$form_state) {
+    // Modify $form_state['values'] to adjust saved values.
+  }
+
+  /**
+   * Implements \Drupal\editor\Plugin\EditorInterface::generateJSSettings().
+   */
+  public function generateJSSettings(Editor $editor) {
+    return array();
+  }
+}
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/EditorInterface.php b/core/modules/editor/lib/Drupal/editor/Plugin/EditorInterface.php
new file mode 100644
index 0000000..b1df816
--- /dev/null
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/EditorInterface.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\editor\Plugin\EditorInterface.
+ */
+
+namespace Drupal\editor\Plugin;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\editor\Plugin\Core\Entity\Editor;
+
+/**
+ * Defines an interface for configurable text editors.
+ *
+ * Modules implementing this interface should instead extend the EditorBase
+ * class, which provides default implementations of each method where
+ * appropriate.
+ */
+interface EditorInterface extends PluginInspectionInterface {
+
+  /**
+   * Returns the default settings for this configurable text editor.
+   *
+   * @return array
+   *   An array of settings as they would be stored by a configured text editor
+   *   entity (\Drupal\editor\Plugin\Core\Entity\Editor).
+   */
+  function defaultSettings();
+
+  /**
+   * Returns a settings form to configure this text editor.
+   *
+   * Note that this form will be a subform of filter_admin_format_form().
+   * Settings within this subform are validated by settingsFormValidate() and
+   * then saved exactly as specified in $form_state['values'] by
+   * editor_form_filter_admin_format_submit().
+   *
+   * If the editor's behavior depends on extensive options and/or external data,
+   * then the implementing module can choose to provide a separate, global
+   * configuration page rather than per-text-format settings. In that case, this
+   * form should provide a link to the separate settings page.
+   *
+   * @param array $form
+   *   The prepopulated form array of the filter administration form.
+   * @param array $form_state
+   *   The state of the entire configuration form.
+   * @param \Drupal\editor\Plugin\Core\Entity\Editor $editor
+   *   A configured text editor object.
+   * @return array
+   *   A render array for the settings form.
+   */
+  function settingsForm(array &$form, array &$form_state, Editor $editor);
+
+  /**
+   * Validates the settings form for an editor.
+   *
+   * The contents of the editor settings are located in
+   * $form_state['values']['editor_settings']. Calls to form_set_error() should
+   * reflect this location in the settings form.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param array $form_state
+   *   A reference to a keyed array containing the current state of the form.
+   */
+  function settingsFormValidate(array $form, array &$form_state);
+
+  /**
+   * Modifies any values in the form state to prepare them for saving.
+   *
+   * Values in $form_state['values']['editor_settings'] are saved by Editor
+   * module in editor_form_filter_admin_format_submit().
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param array $form_state
+   *   A reference to a keyed array containing the current state of the form.
+   */
+  function settingsFormSubmit(array $form, array &$form_state);
+
+  /**
+   * Generates JavaScript settings for a configured text editor object.
+   *
+   * Most text editors use JavaScript to provide a WYSIWYG or toolbar on the
+   * client-side interface. This method can be used to convert internal settings
+   * of the text editor into JavaScript variables that will be accessible when
+   * the text editor is loaded.
+   *
+   * @param \Drupal\editor\Plugin\Core\Entity\Editor $editor
+   *   A configured text editor object.
+   * @return array
+   *   An array of settings that will be added to the page for use by this text
+   *   editor's JavaScript integration.
+   */
+  function generateJSSettings(Editor $editor);
+
+}
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php b/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php
new file mode 100644
index 0000000..c391540
--- /dev/null
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\editor\Plugin\EditorManager.
+ */
+
+namespace Drupal\editor\Plugin;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Plugin\Discovery\AlterDecorator;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\CacheDecorator;
+
+/**
+ * Configurable text editor manager.
+ */
+class EditorManager extends PluginManagerBase {
+
+  /**
+   * Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
+   */
+  public function __construct() {
+    $this->discovery = new AnnotatedClassDiscovery('editor', 'editor');
+    $this->discovery = new AlterDecorator($this->discovery, 'editor_info');
+    $this->discovery = new CacheDecorator($this->discovery, 'editor');
+    $this->factory = new DefaultFactory($this->discovery);
+  }
+
+  /**
+   * Populate a key-value pair of available text editors.
+   *
+   * @return array
+   *   An array of translated text editor labels, keyed by ID.
+   */
+  public function listOptions() {
+    $options = array();
+    foreach ($this->getDefinitions() as $key => $definition) {
+      $options[$key] = $definition['title'];
+    }
+    return $options;
+  }
+}
diff --git a/core/modules/filter/filter.admin.inc b/core/modules/filter/filter.admin.inc
index a62f8e3..a53219d 100644
--- a/core/modules/filter/filter.admin.inc
+++ b/core/modules/filter/filter.admin.inc
@@ -152,6 +152,7 @@ function filter_admin_format_form($form, &$form_state, $format) {
     '#title' => t('Name'),
     '#default_value' => $format->name,
     '#required' => TRUE,
+    '#weight' => -20,
   );
   $form['format'] = array(
     '#type' => 'machine_name',
@@ -163,6 +164,7 @@ function filter_admin_format_form($form, &$form_state, $format) {
       'source' => array('name'),
     ),
     '#disabled' => !empty($format->format),
+    '#weight' => -19,
   );
 
   // Add user role access selection.
@@ -171,6 +173,7 @@ function filter_admin_format_form($form, &$form_state, $format) {
     '#title' => t('Roles'),
     '#options' => array_map('check_plain', user_roles()),
     '#disabled' => $is_fallback,
+    '#weight' => -10,
   );
   if ($is_fallback) {
     $form['roles']['#description'] = t('All roles for this text format must be enabled and cannot be changed.');
