diff --git a/core/modules/ckeditor/ckeditor.libraries.yml b/core/modules/ckeditor/ckeditor.libraries.yml
index 902cb99..68ea65b 100644
--- a/core/modules/ckeditor/ckeditor.libraries.yml
+++ b/core/modules/ckeditor/ckeditor.libraries.yml
@@ -15,6 +15,12 @@ drupal.ckeditor:
     # Ensure to run after core/matchmedia.
     - core/matchmedia
 
+drupal.ckeditor.plugins.drupalimage.drag-and-drop-uploads:
+  version: VERSION
+  css:
+    component:
+      css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css: {}
+
 drupal.ckeditor.plugins.drupalimagecaption:
   version: VERSION
   css:
diff --git a/core/modules/ckeditor/ckeditor.module b/core/modules/ckeditor/ckeditor.module
index 115afe2..54f4793 100644
--- a/core/modules/ckeditor/ckeditor.module
+++ b/core/modules/ckeditor/ckeditor.module
@@ -65,6 +65,9 @@ function ckeditor_ckeditor_css_alter(array &$css, Editor $editor) {
   if ($editor->getFilterFormat()->filters('filter_caption')->status) {
     $css[] = drupal_get_path('module', 'filter') . '/css/filter.caption.css';
   }
+
+  // Add the drupalimage drag-and-drop CSS to enhance UX.
+  $css[] = drupal_get_path('module', 'ckeditor') . '/css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css';
 }
 
 /**
diff --git a/core/modules/ckeditor/css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css b/core/modules/ckeditor/css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css
new file mode 100644
index 0000000..cc29f91
--- /dev/null
+++ b/core/modules/ckeditor/css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css
@@ -0,0 +1,6 @@
+/**
+ * Needed in CKEditor, to enhance the UX of the drag-and-drop image uploading.
+ */
+img[data-cke-drupalimage-preview] {
+  opacity: 0.3;
+}
diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index 497393f..a63744d 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -215,6 +215,7 @@
 
       // Add a consistent dialog class.
       var classes = dialogSettings.dialogClass ? dialogSettings.dialogClass.split(' ') : [];
+      classes.push('ckeditor-drupal-dialog');
       classes.push('ui-dialog--narrow');
       dialogSettings.dialogClass = classes.join(' ');
       dialogSettings.autoResize = window.matchMedia('(min-width: 600px)').matches;
@@ -248,7 +249,7 @@
   };
 
   // Moves the dialog to the top of the CKEDITOR stack.
-  $(window).on('dialogcreate', function (e, dialog, $element, settings) {
+  $(window).on('dialogcreate', function (e, dialog) {
     $('.ui-dialog--narrow').css('zIndex', CKEDITOR.config.baseFloatZIndex + 1);
   });
 
@@ -258,6 +259,13 @@
       $(this).remove();
     });
   });
+  // @fires event:editor:dialogopen
+  $(window).on('dialog:aftercreate', function (e, dialog, $element, settings) {
+    if (!$element.parent().hasClass('ckeditor-drupal-dialog')) {
+      return;
+    }
+    $(window).trigger('editor:dialogopen', [dialog, $element]);
+  });
 
   // Respond to dialogs that are saved, sending data back to CKEditor.
   $(window).on('editor:dialogsave', function (e, values) {
@@ -267,10 +275,16 @@
   });
 
   // Respond to dialogs that are closed, removing the current save handler.
+  // @fires event:editor:dialogclose
   $(window).on('dialog:afterclose', function (e, dialog, $element) {
+    if (!$element.parent().hasClass('ckeditor-drupal-dialog')) {
+      return;
+    }
+
     if (Drupal.ckeditor.saveCallback) {
       Drupal.ckeditor.saveCallback = null;
     }
+    $(window).trigger('editor:dialogclose', [dialog, $element]);
   });
 
   // Set the CKEditor cache-busting string to the same value as Drupal.
diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
index 0025664..59dfeba 100644
--- a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js
@@ -18,7 +18,7 @@
   'use strict';
 
   CKEDITOR.plugins.add('drupalimage', {
-    requires: 'image2',
+    requires: 'image2,uploadwidget',
     icons: 'drupalimage',
     hidpi: true,
 
@@ -267,6 +267,76 @@
         }
       });
 
+      var fileTools = CKEDITOR.fileTools;
+      fileTools.addUploadWidget(editor, 'fileReader', {
+        loadMethod: 'load',
+        supportedTypes: /image\/(gif|png|jpg|jpeg)/,
+        fileToElement: function () {
+          var el = new CKEDITOR.dom.element('span');
+          el.setText('Loading...');
+          return el;
+        },
+        onLoaded: function (loader) {
+          var el = new CKEDITOR.dom.element('img');
+          el.setAttribute('data-cke-drupalimage-preview', true);
+          el.setAttribute('src', loader.data);
+          this.replaceWith(el.getOuterHtml());
+        }
+      });
+
+      editor.on('paste', function (evt) {
+        var file = evt.data.dataTransfer.getFile(0);
+        if (typeof file === 'undefined') {
+          return;
+        }
+        if (CKEDITOR.fileTools.isTypeSupported(file, /image\/(gif|png|jpg|jpeg)/)) {
+          var loader = editor.uploadRepository.create(file);
+          loader.load();
+
+          editor.execCommand('image');
+
+          $(window).one('editor:dialogopen', function (e, dialog, $element, settings) {
+            var form = $element.find('form.editor-image-dialog');
+            var formData = new FormData();
+            var uploadButtonId = '#' + form.find('[data-drupal-selector=edit-fid-upload-button]').attr('id');
+
+            var ajaxObject = getAjaxObject(uploadButtonId);
+            // Add the dropped image file to the form.
+            // @see Drupal.Ajax.prototype.beforeSerialize
+            ajaxObject.beforeSerialize = function (element_settings, options) {
+              formData.append('files[fid]', file);
+              $.each(this.$form.serializeArray(), function (k, v) {
+                formData[v.name] = v.value;
+                formData.append(v.name, v.value);
+              });
+              options.data = formData;
+              // jQuery.ajax() by default sets the contentType as
+              // "application/x-www-form-urlencoded; charset=UTF-8". As of
+              // jQuery 1.6 you can pass false to tell jQuery to not set any
+              // content type header.
+              // @see http://api.jquery.com/jquery.ajax/
+              options.contentType = false;
+              // By default, data passed in to the data option as an object. In
+              // order to send a DOMDocument, or other non-processed data, we
+              // need to set this option to false.
+              // @see http://api.jquery.com/jquery.ajax/
+              options.processData = false;
+            };
+
+            ajaxObject.execute();
+          });
+
+          $(window).one('editor:dialogclose', function (e, dialog, $element, settings) {
+            var preview = editor.document.findOne('[data-cke-drupalimage-preview]');
+            if (preview) {
+              preview.remove();
+              // Prevent reverting back to the preview image when using undo.
+              editor.fire('updateSnapshot');
+            }
+          });
+        }
+      });
+
       // Register the toolbar button.
       if (editor.ui.addButton) {
         editor.ui.addButton('DrupalImage', {
@@ -363,6 +433,25 @@
     return null;
   }
 
+  /**
+   * Gets a Drupal AJAX instance by selector id.
+   *
+   * @param {string} id
+   *   The selector id.
+   * @return {Object}
+   *   The Drupal AJAX instance, or null.
+   */
+  function getAjaxObject(id) {
+    var ajaxInstance = null;
+    $.each(Drupal.ajax.instances, function (k, v) {
+      if (v !== null && v.selector === id) {
+        ajaxInstance = Drupal.ajax.instances[k];
+        return ajaxInstance;
+      }
+    });
+    return ajaxInstance;
+  }
+
   // Expose an API for other plugins to interact with drupalimage widgets.
   CKEDITOR.plugins.drupalimage = {
     getFocusedWidget: getFocusedWidget
diff --git a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
index 170305d..641e607 100644
--- a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
+++ b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
@@ -365,6 +365,7 @@ public function getLangcodes() {
   public function getLibraries(Editor $editor) {
     $libraries = array(
       'ckeditor/drupal.ckeditor',
+      'ckeditor/drupal.ckeditor.plugins.drupalimage.drag-and-drop-uploads',
     );
 
     // Get the required libraries for any enabled plugins.
diff --git a/core/themes/stable/css/ckeditor/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css b/core/themes/stable/css/ckeditor/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css
new file mode 100644
index 0000000..cc29f91
--- /dev/null
+++ b/core/themes/stable/css/ckeditor/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css
@@ -0,0 +1,6 @@
+/**
+ * Needed in CKEditor, to enhance the UX of the drag-and-drop image uploading.
+ */
+img[data-cke-drupalimage-preview] {
+  opacity: 0.3;
+}
diff --git a/core/themes/stable/stable.info.yml b/core/themes/stable/stable.info.yml
index 3476833..f0dcb56 100644
--- a/core/themes/stable/stable.info.yml
+++ b/core/themes/stable/stable.info.yml
@@ -17,6 +17,10 @@ libraries-override:
     css:
       state:
         css/ckeditor.css: css/ckeditor/ckeditor.css
+  ckeditor/drupal.ckeditor.plugins.drupalimage.drag-and-drop-uploads:
+    css:
+      component:
+        css/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css: css/ckeditor/plugins/drupalimage/ckeditor.drag-and-drop-uploads.css
   ckeditor/drupal.ckeditor.plugins.drupalimagecaption:
     css:
       component:
