diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index acd2cf2..8c8af02 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -10,6 +10,15 @@
       format.editorSettings.drupal = {
         format: format.format
       };
+
+      // CKEditor initializes itself in a read-only state if the 'disabled'
+      // attribute is set. It does not respect the 'readonly' attribute,
+      // however, so we set the 'readOnly' configuration property manually in
+      // that case.
+      if (element.hasAttribute('readonly')) {
+        format.editorSettings.readOnly = true;
+      }
+
       return !!CKEDITOR.replace(element, format.editorSettings);
     },
 
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index 9da1540..00ab94c 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -257,9 +257,9 @@ function editor_pre_render_format($element) {
   }
 
   // filter_process_format() copies properties to the expanded 'value' child
-  // element. Skip this text format widget, if it contains no 'format' or when
-  // the current user does not have access to edit the value.
-  if (!isset($element['format']) || !empty($element['value']['#disabled'])) {
+  // element, including the #pre_render property. Skip this text format widget,
+  // if it contains no 'format'.
+  if (!isset($element['format'])) {
     return $element;
   }
   $format_ids = array_keys($element['format']['format']['#options']);
