diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 89450cc6fe..67a077a8f2 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\file\Entity\File;
 use Drupal\field\FieldStorageConfigInterface;
@@ -498,3 +499,84 @@ function image_field_config_delete(FieldConfigInterface $field) {
     \Drupal::service('file.usage')->delete($file, 'image', 'default_image', $field->uuid());
   }
 }
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Alters the image dialog form for text editor, to allow the user to select an
+ * image style.
+ *
+ * @see \Drupal\editor\Form\EditorImageDialog::buildForm()
+ */
+function image_form_editor_image_dialog_alter(&$form, FormStateInterface $form_state) {
+  /** @var \Drupal\editor\EditorInterface $editor */
+  $editor = $form_state->getBuildInfo()['args'][0];
+
+  // Alter the editor image dialog when image style functionality is available.
+  if ($editor->getFilterFormat()->filters('filter_image_style')->status) {
+    // Get the image (<img>) that is being edited on the client.
+    $image_element = $form_state->getStorage()['image_element'];
+
+    // Get an array of image styles to present as options for selection.
+    $image_style_options = image_style_options(FALSE);
+
+    // Add a select element to choose an image style.
+    $form['image_style']['selection'] = [
+      '#title' => t('Image style'),
+      '#type' => 'select',
+      '#default_value' => isset($image_element['data-image-style']) ? $image_element['data-image-style'] : NULL,
+      '#options' => $image_style_options,
+      '#required' => TRUE,
+      '#parents' => ['attributes', 'data-image-style'],
+    ];
+
+    $form['actions']['save_modal']['#validate'][] = 'image_form_editor_image_dialog_validate';
+  }
+}
+
+/**
+ * Form validation handler for EditorImageDialog.
+ *
+ * Ensures the image shown in the text editor matches the chosen image style.
+ *
+ * @see \Drupal\editor\Form\EditorImageDialog::buildForm()
+ * @see \Drupal\editor\Form\EditorImageDialog::validateForm()
+ * @see image_form_editor_image_dialog_alter()
+ */
+function image_form_editor_image_dialog_validate(array &$form, FormStateInterface &$form_state) {
+  if (!empty($form_state->getValue('fid')[0])) {
+
+    $attributes = &$form_state->getValue('attributes');
+
+    /** @var \Drupal\image\ImageStyleInterface $image_style */
+    $image_style = ImageStyle::load($attributes['data-image-style']);
+
+    /** @var \Drupal\file\FileInterface $file */
+    $file = File::load($form_state->getValue('fid')[0]);
+
+    $uri = $file->getFileUri();
+
+    // Set the 'src' attribute to the image style URL. FilterImageStyle will
+    // look at the 'data-editor-file-uuid' attribute, not the 'src' attribute to
+    // render the appropriate output.
+    $image_url = $image_style->buildUrl($uri);
+    $attributes['src'] = file_url_transform_relative($image_url);
+
+    /** @var \Drupal\Core\Image\ImageInterface $image */
+    $image = \Drupal::service('image.factory')->get($uri);
+
+    if ($image->isValid()) {
+      // Get the original width and height of the image.
+      $dimensions = [
+        'width' => $image->getWidth(),
+        'height' => $image->getHeight(),
+      ];
+
+      // Transform the 'width' and 'height' dimensions of the image based on the
+      // image style.
+      $image_style->transformDimensions($dimensions, $attributes['src']);
+      $attributes['width'] = $dimensions['width'];
+      $attributes['height'] = $dimensions['height'];
+    }
+  }
+}
diff --git a/core/modules/image/image.post_update.php b/core/modules/image/image.post_update.php
index 04d8c4b7b9..7548ec436a 100644
--- a/core/modules/image/image.post_update.php
+++ b/core/modules/image/image.post_update.php
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\filter\Entity\FilterFormat;
 
 /**
  * Saves the image style dependencies into form and view display entities.
@@ -20,3 +21,28 @@ function image_post_update_image_style_dependencies() {
     $display->save();
   }
 }
+
+/**
+ * Add filter image style to basic_html and full_html filter formats.
+ */
+function image_post_update_enable_filter_image_style() {
+  $formats = ['basic_html' => 11, 'full_html' => 12];
+  foreach ($formats as $format => $weight) {
+    if ($format = FilterFormat::load($format)) {
+      $format->setFilterConfig('filter_image_style', ['status' => TRUE, 'weight' => $weight]);
+      // Update the allowed html tags of filter_html filter if its enabled.
+      if (($filter = $format->filters('filter_html'))) {
+        $config = $filter->getConfiguration();
+        $allowed_html = !empty($config['settings']['allowed_html']) ? $config['settings']['allowed_html'] : NULL;
+        $matches = [];
+        if ($allowed_html && preg_match('/<img([^>]*)>/', $allowed_html, $matches)) {
+          $new_attributes = array_filter(explode(' ', $matches[1]));
+          $new_attributes[] = 'data-image-style';
+          $config['settings']['allowed_html'] = preg_replace('/<img([^>]*)>/', '<img ' . implode(' ', array_unique($new_attributes)) . '>', $allowed_html);
+          $format->setFilterConfig('filter_html', $config);
+        }
+      }
+      $format->save();
+    }
+  }
+}
diff --git a/core/modules/image/js/plugins/drupalimagestyle/plugin.js b/core/modules/image/js/plugins/drupalimagestyle/plugin.js
new file mode 100644
index 0000000000..ef8eae1d53
--- /dev/null
+++ b/core/modules/image/js/plugins/drupalimagestyle/plugin.js
@@ -0,0 +1,112 @@
+/**
+ * @file
+ * Drupal Image Style plugin.
+ *
+ * This alters the existing CKEditor image2 widget plugin, which is already
+ * altered by the Drupal Image plugin, to allow for the data-image-style
+ * attribute to be set.
+ *
+ * @ignore
+ */
+
+(function (CKEDITOR) {
+
+  'use strict';
+
+  CKEDITOR.plugins.add('drupalimagestyle', {
+    requires: 'drupalimage',
+
+    beforeInit: function (editor) {
+      // Override the image2 widget definition to handle the additional
+      // data-image-style attributes.
+      editor.on('widgetDefinition', function (event) {
+        var widgetDefinition = event.data;
+        if (widgetDefinition.name !== 'image') {
+          return;
+        }
+        // Override default features definitions for drupalimagestyle.
+        CKEDITOR.tools.extend(widgetDefinition.features, {
+          drupalimagestyle: {
+            requiredContent: 'img[data-image-style]'
+          }
+        }, true);
+
+        // Override requiredContent & allowedContent.
+        var requiredContent = widgetDefinition.requiredContent.getDefinition();
+        requiredContent.attributes['data-image-style'] = '';
+        widgetDefinition.requiredContent = new CKEDITOR.style(requiredContent);
+        widgetDefinition.allowedContent.img.attributes['!data-image-style'] = true;
+
+        // Decorate downcast().
+        var originalDowncast = widgetDefinition.downcast;
+        widgetDefinition.downcast = function (element) {
+          var img = originalDowncast.call(this, element);
+          if (!img) {
+            img = findElementByName(element, 'img');
+          }
+          img.attributes['data-image-style'] = this.data['data-image-style'];
+          return img;
+        };
+
+        // Decorate upcast().
+        var originalUpcast = widgetDefinition.upcast;
+        widgetDefinition.upcast = function (element, data) {
+          if (element.name !== 'img' || !element.attributes['data-entity-type'] || !element.attributes['data-entity-uuid']) {
+            return;
+          }
+          // Don't initialize on pasted fake objects.
+          else if (element.attributes['data-cke-realelement']) {
+            return;
+          }
+
+          // Parse the data-image-style attribute.
+          data['data-image-style'] = element.attributes['data-image-style'];
+
+          // Upcast after parsing so correct element attributes are parsed.
+          element = originalUpcast.call(this, element, data);
+
+          return element;
+        };
+
+        // Protected; keys of the widget data to be sent to the Drupal dialog.
+        // Append to the values defined by the drupalimage plugin.
+        // @see core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+        CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
+          'data-image-style': 'data-image-style'
+        });
+      // Low priority to ensure drupalimage's event handler runs first.
+      }, null, null, 20);
+    }
+  });
+
+  /**
+   * Finds an element by its name.
+   *
+   * Function will check first the passed element itself and then all its
+   * children in DFS order.
+   *
+   * @param {CKEDITOR.htmlParser.element} element
+   *   The element to search.
+   * @param {string} name
+   *   The element name to search for.
+   *
+   * @return {?CKEDITOR.htmlParser.element}
+   *   The found element, or null.
+   */
+  function findElementByName(element, name) {
+    if (element.name === name) {
+      return element;
+    }
+
+    var found = null;
+    element.forEach(function (el) {
+      if (el.name === name) {
+        found = el;
+        // Stop here.
+        return false;
+      }
+    }, CKEDITOR.NODE_ELEMENT);
+    return found;
+  }
+
+})(CKEDITOR);
diff --git a/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php b/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php
new file mode 100644
index 0000000000..98fbd1ac53
--- /dev/null
+++ b/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\image\Plugin\CKEditorPlugin;
+
+use Drupal\ckeditor\CKEditorPluginManager;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\editor\Entity\Editor;
+use Drupal\ckeditor\CKEditorPluginInterface;
+use Drupal\ckeditor\CKEditorPluginContextualInterface;
+
+/**
+ * Defines the "drupalimagestyle" plugin.
+ *
+ * @CKEditorPlugin(
+ *   id = "drupalimagestyle",
+ *   label = @Translation("Image style"),
+ *   module = "ckeditor"
+ * )
+ */
+class DrupalImageStyle extends PluginBase implements CKEditorPluginInterface, CKEditorPluginContextualInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isInternal() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDependencies(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLibraries(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFile() {
+    return drupal_get_path('module', 'image') . '/js/plugins/drupalimagestyle/plugin.js';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfig(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEnabled(Editor $editor) {
+    if (!$editor->hasAssociatedFilterFormat()) {
+      return FALSE;
+    }
+
+    // Automatically enable this plugin if the text format associated with this
+    // text editor uses the filter_image_style filter and the DrupalImage button
+    // is enabled.
+    $format = $editor->getFilterFormat();
+    if ($format->filters('filter_image_style')->status) {
+      $toolbarButtons = CKEditorPluginManager::getEnabledButtons($editor);
+      return in_array('DrupalImage', $toolbarButtons);
+    }
+
+    return FALSE;
+  }
+
+}
diff --git a/core/modules/image/src/Plugin/Filter/FilterImageStyle.php b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
new file mode 100644
index 0000000000..77a36b4428
--- /dev/null
+++ b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
@@ -0,0 +1,245 @@
+<?php
+
+namespace Drupal\image\Plugin\Filter;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Image\ImageFactory;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\Render\RenderContext;
+use Drupal\filter\FilterProcessResult;
+use Drupal\filter\Plugin\FilterBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a filter to render inline images as image styles.
+ *
+ * @Filter(
+ *   id = "filter_image_style",
+ *   module = "image",
+ *   title = @Translation("Display image styles"),
+ *   description = @Translation("Uses the data-image-style attribute on &lt;img&gt; tags to display image styles."),
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
+ * )
+ */
+class FilterImageStyle extends FilterBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity repository.
+   *
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface
+   */
+  protected $entityRepository;
+
+  /**
+   * The image factory.
+   *
+   * @var \Drupal\Core\Image\ImageFactory
+   */
+  protected $imageFactory;
+
+  /**
+   * The renderer.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
+   * Constructs a \Drupal\image\Plugin\Filter\FilterImageStyle object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository.
+   * @param \Drupal\Core\Image\ImageFactory $image_factory
+   *   The image factory.
+   * @param \Drupal\Core\Render\RendererInterface $renderer
+   *   The renderer.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, ImageFactory $image_factory, RendererInterface $renderer) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityRepository = $entity_repository;
+    $this->imageFactory = $image_factory;
+    $this->renderer = $renderer;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('entity.repository'), $container->get('image.factory'), $container->get('renderer'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    if (stristr($text, 'data-image-style') !== FALSE) {
+      // Load all image styles so each image found in the text can be checked
+      // against a valid image style.
+      $image_styles = $this->loadImageStyles();
+
+      $dom = Html::load($text);
+      $xpath = new \DOMXPath($dom);
+
+      // Process each image element found with the necessary attributes.
+      /** @var \DOMElement $dom_element */
+      foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid and @data-image-style]') as $dom_element) {
+        // Get the UUID and image style for the file.
+        $file_uuid = $dom_element->getAttribute('data-entity-uuid');
+        $image_style_id = $dom_element->getAttribute('data-image-style');
+
+        // If the image style is not a valid one, then don't transform the HTML.
+        if (empty($file_uuid) || !in_array($image_style_id, $image_styles)) {
+          continue;
+        }
+
+        // Transform the HTML for the img element by applying an image style.
+        $altered_img_markup = $this->getImageStyleHtml($file_uuid, $image_style_id, $dom_element);
+        $altered_img = $dom->createDocumentFragment();
+        $altered_img->appendXML($altered_img_markup);
+        $dom_element->parentNode->replaceChild($altered_img, $dom_element);
+      }
+
+      return new FilterProcessResult(Html::serialize($dom));
+    }
+
+    // Process the filter if no image style img elements are found.
+    return new FilterProcessResult($text);
+  }
+
+  /**
+   * Loads the available image style names.
+   *
+   * @return string[]
+   *   Array keys of the available image styles.
+   */
+  protected function loadImageStyles() {
+    return array_keys($this->entityTypeManager->getStorage('image_style')->loadMultiple());
+  }
+
+  /**
+   * Gets the the width and height of an image based on the file UUID.
+   *
+   * @param string $file_uuid
+   *   The UUID for the file.
+   *
+   * @return array
+   *   The image information.
+   */
+  protected function getImageInfo($file_uuid) {
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $this->entityRepository->loadEntityByUuid('file', $file_uuid);
+
+    // Determine uri, width and height of the source image.
+    $image_uri = $image_width = $image_height = NULL;
+    $image = $this->imageFactory->get($file->getFileUri());
+    if ($image->isValid()) {
+      $image_uri = $file->getFileUri();
+      $image_width = $image->getWidth();
+      $image_height = $image->getHeight();
+    }
+
+    return [
+      'uri' => $image_uri,
+      'width' => $image_width,
+      'height' => $image_height,
+    ];
+  }
+
+  /**
+   * Removes attributes that will be generated from image style theme function.
+   *
+   * @param \DOMElement $dom_element
+   *   The DOM element for the img element.
+   *
+   * @return array
+   *   The attributes array.
+   */
+  protected function prepareImageAttributes(\DOMElement $dom_element) {
+    // Remove attributes that are generated by the image style.
+    $dom_element->removeAttribute('width');
+    $dom_element->removeAttribute('height');
+    $dom_element->removeAttribute('src');
+
+    // Make sure all non-regenerated attributes are retained.
+    $attributes = [];
+    for ($i = 0; $i < $dom_element->attributes->length; $i++) {
+      $attr = $dom_element->attributes->item($i);
+      $attributes[$attr->name] = $attr->value;
+    }
+
+    return $attributes;
+  }
+
+  /**
+   * Gets the HTML for the image element after image style is applied.
+   *
+   * @param string $file_uuid
+   *   The UUID for the file.
+   * @param string $image_style_id
+   *   The ID for the image style.
+   * @param \DOMElement $dom_element
+   *   The DOM element for the image element.
+   *
+   * @return string
+   *   The img element with the image style applied.
+   */
+  protected function getImageStyleHtml($file_uuid, $image_style_id, \DOMElement $dom_element) {
+    $image_info = $this->getImageInfo($file_uuid);
+
+    // Remove attributes that will be generated by the image style.
+    $attributes = $this->prepareImageAttributes($dom_element);
+
+    // Re-render as an image style.
+    $image = [
+      '#theme' => 'image_style',
+      '#style_name' => $image_style_id,
+      '#uri' => $image_info['uri'],
+      '#width' => $image_info['width'],
+      '#height' => $image_info['height'],
+      '#attributes' => $attributes,
+    ];
+
+    $output = $this->renderer->executeInRenderContext(new RenderContext(), function () use (&$image) {
+      return $this->renderer->render($image);
+    });
+
+    return $output;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tips($long = FALSE) {
+    if ($long) {
+      $image_styles = $this->loadImageStyles();
+      $list = '<code>' . implode('</code>, <code>', $image_styles) . '</code>';
+      return t('
+        <p>You can display images using site-wide styles by adding a <code>data-image-style</code> attribute, whose values is one of the image style machine names: !image-style-machine-name-list.</p>', ['!image-style-machine-name-list' => $list]);
+    }
+    else {
+      return t('You can display images using site-wide styles by adding a data-image-style attribute.');
+    }
+
+  }
+
+}
diff --git a/core/modules/image/src/Tests/Update/ImageUpdateTextFormatsTest.php b/core/modules/image/src/Tests/Update/ImageUpdateTextFormatsTest.php
new file mode 100644
index 0000000000..7f01c1f568
--- /dev/null
+++ b/core/modules/image/src/Tests/Update/ImageUpdateTextFormatsTest.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\image\Tests\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests Image update path.
+ *
+ * @group image
+ */
+class ImageUpdateTextFormatsTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Tests image_post_update_enable_filter_image_style().
+   *
+   * @see image_post_update_enable_filter_image_style()
+   */
+  public function testPostUpdateFilterImageStyle() {
+    // Check that basic_html and full_html format does not have filter_image_style filter applied.
+    $config_factory = \Drupal::configFactory();
+    $basic_html_data = $config_factory->get('filter.format.basic_html')->get();
+    $this->assertFalse(isset($basic_html_data['filters']['filter_image_style']), 'Prior to running the update the "filter_image_style" filter does not applied to basic_html format.');
+    $full_html_data = $config_factory->get('filter.format.full_html')->get();
+    $this->assertFalse(isset($full_html_data['filters']['filter_image_style']), 'Prior to running the update the "filter_image_style" filter does not applied to full_html format.');
+
+    // Run updates.
+    $this->runUpdates();
+
+    // Check that the filter_format entities have been updated.
+    $config_factory = \Drupal::configFactory();
+    $basic_html_data = $config_factory->get('filter.format.basic_html')->get();
+    $this->assertTrue(isset($basic_html_data['filters']['filter_image_style']), 'After running the update the "filter_image_style" filter applied to basic_html format.');
+    $full_html_data = $config_factory->get('filter.format.full_html')->get();
+    $this->assertTrue(isset($full_html_data['filters']['filter_image_style']), 'After running the update the "filter_image_style" filter applied to full_html format.');
+
+  }
+
+}
diff --git a/core/modules/image/tests/src/Functional/FilterImageStyleTest.php b/core/modules/image/tests/src/Functional/FilterImageStyleTest.php
new file mode 100644
index 0000000000..2c403d67f7
--- /dev/null
+++ b/core/modules/image/tests/src/Functional/FilterImageStyleTest.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace Drupal\Tests\image\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\file\Entity\File;
+use Drupal\Core\Url;
+
+/**
+ * Tests FilterImageStyle conversion of inline images to utilize image styles.
+ *
+ * @coversDefaultClass \Drupal\image\Plugin\Filter\FilterImageStyle
+ * @group image
+ */
+class FilterImageStyleTest extends BrowserTestBase {
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['filter', 'file', 'editor', 'node', 'image'];
+
+  /**
+   * A text format allowing images and with FilterImageStyle applied.
+   *
+   * @var \Drupal\Filter\FilterFormatInterface
+   */
+  protected $format;
+
+  /**
+   * Tasks common to all tests.
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->format = FilterFormat::create([
+      'format' => $this->randomMachineName(),
+      'name' => $this->randomString(),
+      'filters' => [
+        'filter_html' => [
+          'status' => TRUE,
+          'settings' => [
+            'allowed_html' => '<img src alt data-entity-type data-entity-uuid data-align data-caption data-image-style width height>',
+          ],
+        ],
+        'filter_image_style' => ['status' => TRUE],
+        'editor_file_reference' => ['status' => TRUE],
+      ],
+    ]);
+    $this->format->save();
+
+    $user = $this->drupalCreateUser(['access content', 'administer nodes']);
+    $this->drupalLogin($user);
+
+    $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
+  }
+
+  /**
+   * Helper function to create a test node with configurable image html.
+   */
+  protected function nodeHelper($image_html) {
+    $node = $this->drupalCreateNode([
+      'type' => 'page',
+      'title' => $this->randomString(),
+      'body' => [
+        [
+          'format' => $this->format->id(),
+          'value' => $image_html,
+        ],
+      ],
+    ]);
+    $node->save();
+
+    $this->drupalGet($node->toUrl());
+    $this->assertSession()->statusCodeEquals(200);
+  }
+
+  /**
+   * Tests that images not uploaded through media module are unmolested.
+   */
+  public function testImageNoStyle() {
+    $file_url = Url::fromUri('base:core/themes/bartik/screenshot.png')->toString();
+
+    $image_html = '<img src="' . $file_url . '" width="220">';
+    $this->nodeHelper($image_html);
+
+    /** @var \Behat\Mink\Element\NodeElement $img_element */
+    $image_element = $this->getSession()->getPage()->find('css', "img");
+    $this->assertFalse(empty($image_element));
+
+    $this->assertFalse($image_element->hasAttribute('class'));
+    $this->assertEquals($file_url, $image_element->getAttribute('src'));
+    $this->assertEquals('220', $image_element->getAttribute('width'));
+    $this->assertFalse($image_element->hasAttribute('height'));
+  }
+
+  /**
+   * Tests image style modification of images.
+   */
+  public function testImageStyle() {
+    $this->assertTrue(array_key_exists('medium', $this->container->get('entity_type.manager')->getStorage('image_style')->loadMultiple()));
+
+    $file = File::create(['uri' => 'core/themes/bartik/screenshot.png']);
+    $file->save();
+
+    $image_html = '<img src="' . file_url_transform_relative($file->url()) . '" data-entity-type="file" data-entity-uuid="' . $file->uuid() . '" data-image-style="medium" width="220">';
+    $this->nodeHelper($image_html);
+
+    /** @var \Behat\Mink\Element\NodeElement $img_element */
+    $image_element = $this->getSession()->getPage()->find('css', 'img.image-style-medium');
+    $this->assertFalse(empty($image_element));
+
+    $this->assertTrue(strpos($image_element->getAttribute('src'), 'medium'));
+    $this->assertEquals('220', $image_element->getAttribute('width'));
+    $this->assertEquals('164', $image_element->getAttribute('height'));
+  }
+
+}
diff --git a/core/modules/image/tests/src/FunctionalJavascript/AddImageTest.php b/core/modules/image/tests/src/FunctionalJavascript/AddImageTest.php
new file mode 100644
index 0000000000..e4cc8f6fb3
--- /dev/null
+++ b/core/modules/image/tests/src/FunctionalJavascript/AddImageTest.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Drupal\Tests\image\FunctionalJavascript;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\Tests\TestFileCreationTrait;
+use Drupal\editor\Entity\Editor;
+use Drupal\Core\Url;
+
+/**
+ * Tests the JavaScript functionality of the drupalimagestyle CKEditor plugin.
+ *
+ * @group image
+ */
+class AddImageTest extends JavascriptTestBase {
+
+  use TestFileCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['filter', 'file', 'node', 'image', 'ckeditor'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $format = FilterFormat::create([
+      'format' => 'filtered_html',
+      'name' => $this->randomString(),
+      'filters' => [
+        'filter_image_style' => ['status' => TRUE],
+      ],
+    ]);
+    $format->save();
+
+    $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
+
+    Editor::create([
+      'format' => 'filtered_html',
+      'editor' => 'ckeditor',
+    ])->save();
+
+    $user = $this->drupalCreateUser([
+      'access content',
+      'administer nodes',
+      'create page content',
+      'use text format filtered_html',
+    ]);
+    $this->drupalLogin($user);
+  }
+
+  /**
+   * Tests if an image can be placed inline with the data-image-style attribute.
+   */
+  public function testDataImageStyleElement() {
+    $image_url = Url::fromUri('base:core/themes/bartik/screenshot.png')->toString();
+
+    $this->drupalGet('node/add/page');
+    $this->assertSession()->statusCodeEquals(200);
+
+    $page = $this->getSession()->getPage();
+    // Wait for the ckeditor toolbar elements to appear (loading is done).
+    $image_button_selector = 'a.cke_button__drupalimage';
+    $this->assertJsCondition("jQuery('$image_button_selector').length > 0", 20000);
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    $image_button = $page->find('css', $image_button_selector);
+    $this->assertNotEmpty($image_button);
+    $image_button->click();
+    // Wait for the modal form elements to appear (loading is done).
+    $this->assertJsCondition("jQuery('input[data-drupal-selector=\"edit-attributes-alt\"]').length > 0", 20000);
+
+    $url_input = $page->findField('attributes[src]');
+    $this->assertNotEmpty($url_input);
+    $url_input->setValue($image_url);
+
+    $alt_input = $page->findField('attributes[alt]');
+    $this->assertNotEmpty($alt_input);
+    $alt_input->setValue('asd');
+
+    $image_style_input_name = 'attributes[data-image-style]';
+    $this->assertNotEmpty($page->findField($image_style_input_name));
+    $page->selectFieldOption($image_style_input_name, 'thumbnail');
+
+    // To prevent 403s on save, we re-set our request (cookie) state.
+    $this->prepareRequest();
+
+    // Using NodeElement::click() on the button or NodeElement::submit() on the
+    // form generated phantomjs-internal exceptions. This was the only recourse.
+    $script = "jQuery('input[id^=\"edit-actions-save-modal\"]').click()";
+    $this->getSession()->executeScript($script);
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    $source_button = $page->find('css', 'a.cke_button__source');
+    $this->assertNotEmpty($source_button);
+    $source_button->click();
+    $this->assertSession()->assertWaitOnAjaxRequest();
+
+    $this->assertContains('data-image-style="thumbnail"', $page->find('css', 'textarea.cke_source')->getValue());
+  }
+
+}
diff --git a/core/modules/image/tests/src/Kernel/EditorImageStyleDialogTest.php b/core/modules/image/tests/src/Kernel/EditorImageStyleDialogTest.php
new file mode 100644
index 0000000000..9282c32347
--- /dev/null
+++ b/core/modules/image/tests/src/Kernel/EditorImageStyleDialogTest.php
@@ -0,0 +1,171 @@
+<?php
+
+namespace Drupal\Tests\image\Kernel;
+
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Render\RenderContext;
+use Drupal\editor\Entity\Editor;
+use Drupal\editor\Form\EditorImageDialog;
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests EditorImageDialog alteration to add image style selection.
+ *
+ * @see image_form_editor_image_dialog_alter()
+ *
+ * @group image
+ */
+class EditorImageStyleDialogTest extends EntityKernelTestBase {
+
+  /**
+   * Editor for testing.
+   *
+   * @var \Drupal\editor\EditorInterface
+   */
+  protected $editor;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'ckeditor',
+    'editor',
+    'editor_test',
+    'file',
+    'image',
+    'node',
+    'system',
+    'user',
+  ];
+
+  /**
+   * Sets up the test.
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('file');
+    $this->installSchema('system', ['key_value_expire']);
+    $this->installSchema('node', ['node_access']);
+    $this->installSchema('file', ['file_usage']);
+    $this->installConfig(['node']);
+
+    // Install the image module config so we have the medium image style.
+    $this->installConfig('image');
+
+    // Create a node type for testing.
+    $type = NodeType::create(['type' => 'page', 'name' => 'page']);
+    $type->save();
+    node_add_body_field($type);
+    $this->installEntitySchema('user');
+    $this->container->get('router.builder')->rebuild();
+  }
+
+  /**
+   * Fixture to consolidate tasks while making filter status configurable.
+   *
+   * @param bool $enable_image_filter
+   *   Whether to activate filter_image_style in the text format.
+   *
+   * @return array|\Symfony\Component\HttpFoundation\Response
+   *   The submitted form.
+   */
+  protected function setUpForm($enable_image_filter) {
+    $format = FilterFormat::create([
+      'format' => $this->randomMachineName(),
+      'name' => $this->randomString(),
+      'weight' => 0,
+      'filters' => [
+        'filter_image_style' => ['status' => $enable_image_filter],
+      ],
+    ]);
+    $format->save();
+
+    // Set up text editor.
+    /** @var \Drupal\editor\EditorInterface $editor */
+    $editor = Editor::create([
+      'format' => $format->id(),
+      'editor' => 'ckeditor',
+      'image_upload' => [
+        'max_size' => 100,
+        'scheme' => 'public',
+        'directory' => '',
+        'status' => TRUE,
+      ],
+    ]);
+    $editor->save();
+
+    /** @var \Drupal\file\FileInterface $file */
+    $file = file_save_data(file_get_contents($this->root . '/core/modules/image/sample.png'), 'public://');
+
+    $input = [
+      'editor_object' => [
+        'src' => file_url_transform_relative($file->getFileUri()),
+        'alt' => 'Balloons floating above a field.',
+        'data-entity-type' => 'file',
+        'data-entity-uuid' => $file->uuid(),
+      ],
+      'dialogOptions' => [
+        'title' => 'Edit Image',
+        'dialogClass' => 'editor-image-dialog',
+        'autoResize' => 'true',
+      ],
+      '_drupal_ajax' => '1',
+      'ajax_page_state' => [
+        'theme' => 'bartik',
+        'theme_token' => 'some-token',
+        'libraries' => '',
+      ],
+    ];
+    if ($enable_image_filter) {
+      $input['editor_object']['data-image-style'] = 'medium';
+    }
+
+    $form_state = (new FormState())
+      ->setRequestMethod('POST')
+      ->setUserInput($input)
+      ->addBuildInfo('args', [$editor]);
+
+    /** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
+    $form_builder = $this->container->get('form_builder');
+    $form_object = new EditorImageDialog(\Drupal::entityTypeManager()->getStorage('file'));
+    $form_id = $form_builder->getFormId($form_object, $form_state);
+    $form = [];
+
+    /** @var \Drupal\Core\Render\RendererInterface $renderer */
+    $renderer = \Drupal::service('renderer');
+    $renderer->executeInRenderContext(new RenderContext(), function () use (&$form, $form_builder, $form_id, $form_state) {
+      $form = $form_builder->retrieveForm($form_id, $form_state);
+      $form_builder->prepareForm($form_id, $form, $form_state);
+      $form_builder->processForm($form_id, $form, $form_state);
+    });
+
+    return $form;
+  }
+
+  /**
+   * Tests that style selection is hidden when filter_image_style is disabled.
+   */
+  public function testDialogNoStyles() {
+    $form = $this->setUpForm(FALSE);
+
+    $this->assertFalse(array_key_exists('image_style', $form));
+  }
+
+  /**
+   * Tests EditorImageDialog when filter_image_style is enabled.
+   */
+  public function testDialogStyles() {
+    $form = $this->setUpForm(TRUE);
+
+    $this->assertEquals(['large', 'medium', 'thumbnail'], array_keys($form['image_style']['selection']['#options']));
+
+    $this->assertEquals('medium', $form['image_style']['selection']['#default_value']);
+    $this->assertEquals(TRUE, $form['image_style']['selection']['#required']);
+  }
+
+}
diff --git a/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php b/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
index 09e40aa983..00b72dbca5 100644
--- a/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
+++ b/core/modules/system/tests/src/Functional/Update/FilterHtmlUpdateTest.php
@@ -39,7 +39,7 @@ public function testAllowedHtmlUpdate() {
 
     // Make sure we have the expected values after the update.
     $filters_after = [
-      'basic_html' => '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h4 id> <h5 id> <h6 id> <p> <br> <span> <img src alt height width data-align data-caption>',
+      'basic_html' => '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h4 id> <h5 id> <h6 id> <p> <br> <span> <img src alt height width data-align data-caption data-image-style>',
       'restricted_html' => '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h4 id> <h5 id> <h6 id>',
     ];
     foreach ($filters_after as $name => $after) {
diff --git a/core/profiles/standard/config/install/filter.format.basic_html.yml b/core/profiles/standard/config/install/filter.format.basic_html.yml
index 92224c23cf..0e6d143492 100644
--- a/core/profiles/standard/config/install/filter.format.basic_html.yml
+++ b/core/profiles/standard/config/install/filter.format.basic_html.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - editor
+    - image
 name: 'Basic HTML'
 format: basic_html
 weight: 0
@@ -15,7 +16,7 @@ filters:
     status: true
     weight: -10
     settings:
-      allowed_html: '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id> <p> <br> <span> <img src alt height width data-entity-type data-entity-uuid data-align data-caption>'
+      allowed_html: '<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id> <p> <br> <span> <img src alt height width data-entity-type data-entity-uuid data-align data-caption data-image-style>'
       filter_html_help: false
       filter_html_nofollow: false
   filter_align:
@@ -40,5 +41,12 @@ filters:
     id: editor_file_reference
     provider: editor
     status: true
+    weight: 10
+    settings: {  }
+  filter_image_style:
+    id: filter_image_style
+    provider: image
+    status: true
     weight: 11
     settings: {  }
+
diff --git a/core/profiles/standard/config/install/filter.format.full_html.yml b/core/profiles/standard/config/install/filter.format.full_html.yml
index e5febb218a..2f16c8e8d5 100644
--- a/core/profiles/standard/config/install/filter.format.full_html.yml
+++ b/core/profiles/standard/config/install/filter.format.full_html.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - editor
+    - image
 name: 'Full HTML'
 format: full_html
 weight: 1
@@ -33,3 +34,9 @@ filters:
     status: true
     weight: 11
     settings: {  }
+  filter_image_style:
+    id: filter_image_style
+    provider: image
+    status: true
+    weight: 12
+    settings: {  }
