diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index d0ef114..71b5218 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -326,7 +326,14 @@ function image_style_delete_form_submit($form, &$form_state) {
  * @see image_effect_form_submit()
  */
 function image_effect_form($form, &$form_state, $style, $effect) {
-  if (!empty($effect['data'])) {
+  // If no configuration for this image effect, return to the image style page.
+  if (!isset($effect['form callback'])) {
+    drupal_goto('admin/config/media/image-styles/edit/' . $style['name']);
+  }
+  $form_state['image_style'] = $style;
+  $form_state['image_effect'] = $effect;
+
+  if (!empty($effect['ieid'])) {
     $title = t('Edit %label effect', array('%label' => $effect['label']));
   }
   else{
@@ -334,18 +341,19 @@ function image_effect_form($form, &$form_state, $style, $effect) {
   }
   drupal_set_title($title, PASS_THROUGH);
 
-  $form_state['image_style'] = $style;
-  $form_state['image_effect'] = $effect;
-
-  // If no configuration for this image effect, return to the image style page.
-  if (!isset($effect['form callback'])) {
-    drupal_goto('admin/config/media/image-styles/edit/' . $style['name']);
-  }
-
-  $form['#tree'] = TRUE;
   $form['#attached']['css'][drupal_get_path('module', 'image') . '/image.admin.css'] = array();
 
+  $form['ieid'] = array(
+    '#type' => 'value',
+    '#value' => !empty($effect['ieid']) ? $effect['ieid'] : NULL,
+  );
+  $form['name'] = array(
+    '#type' => 'value',
+    '#value' => $effect['name'],
+  );
+
   $form['data'] = call_user_func($effect['form callback'], $effect['data']);
+  $form['data']['#tree'] = TRUE;
 
   // Check the URL for a weight, then the image effect, otherwise use default.
   $form['weight'] = array(
@@ -353,10 +361,10 @@ function image_effect_form($form, &$form_state, $style, $effect) {
     '#value' => isset($_GET['weight']) ? intval($_GET['weight']) : (isset($effect['weight']) ? $effect['weight'] : count($style['effects'])),
   );
 
-  $form['actions'] = array('#tree' => FALSE, '#type' => 'actions');
+  $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
-    '#value' => isset($effect['ieid']) ? t('Update effect') : t('Add effect'),
+    '#value' => !empty($effect['ieid']) ? t('Update effect') : t('Add effect'),
   );
   $form['actions']['cancel'] = array(
     '#type' => 'link',
@@ -371,12 +379,11 @@ function image_effect_form($form, &$form_state, $style, $effect) {
  * Submit handler for updating an image effect.
  */
 function image_effect_form_submit($form, &$form_state) {
-  $effect = array(
-    'name' => $form_state['image_effect']['name'],
-    'data' => $form_state['values']['data'],
-    'weight' => $form_state['values']['weight'],
-  );
+  form_state_values_clean($form_state);
+
+  $effect = $form_state['values'];
   image_effect_save($form_state['image_style']['name'], $effect);
+
   drupal_set_message(t('The image effect was successfully applied.'));
   $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $form_state['image_style']['name'];
 }
@@ -633,12 +640,10 @@ function theme_image_style_effects($variables) {
       $row[] = array('data' => '', 'colspan' => 2);
     }
 
-    if (!isset($form[$key]['#access']) || $form[$key]['#access']) {
-      $rows[] = array(
-        'data' => $row,
-        'class' => !empty($form[$key]['weight']['#access']) || $key == 'new' ? array('draggable') : array(),
-      );
-    }
+    $rows[] = array(
+      'data' => $row,
+      'class' => array('draggable'),
+    );
   }
 
   $header = array(
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index aa05d04..766f8ef 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -8,6 +8,7 @@
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\StreamedResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\File\File;
 
 /**
@@ -1103,33 +1104,30 @@ function image_effect_load($ieid, $style_name) {
 /**
  * Save an image effect.
  *
- * @param $style_name
+ * @param string $style_name
  *   The image style this effect belongs to.
- * @param $effect
- *   An image effect array.
- * @return
- *   An image effect array. In the case of a new effect, 'ieid' will be set.
+ * @param array $effect
+ *   An image effect array. Passed by reference.
+ *
+ * @return array
+ *   The saved image effect array. The 'ieid' key will be set for the effect.
  */
-function image_effect_save($style_name, $effect) {
+function image_effect_save($style_name, &$effect) {
   $config = config('image.style.' . $style_name);
 
-  if (!isset($effect['ieid']) || empty($effect['ieid'])) {
-    // We need to generate the ieid and save the new effect.
-    // The machine name is all the elements of the data array concatenated
-    // together, delimited by underscores.
-    $effect['ieid'] = $effect['name'];
-    foreach ($effect['data'] as $key => $value) {
-      $effect['ieid'] .= '_' . $value;
-    }
-    // @todo The machine name must not use any special non-alphanumeric
-    //   characters, and may also not contain dots/periods, as that is the
-    //   config system's nested key syntax.
-    $effect['ieid'] = preg_replace('@[^a-zA-Z0-9_-]@', '', $effect['ieid']);
+  // Generate a unique ieid for a new effect.
+  if (empty($effect['ieid'])) {
+    $uuid = new Uuid();
+    $effect['ieid'] = $uuid->generate();
   }
   $config->set('effects.' . $effect['ieid'], $effect);
   $config->save();
+
+  // Flush all derivatives that exist for this style, so they are regenerated
+  // with the new or updated effect.
   $style = image_style_load($style_name);
   image_style_flush($style);
+
   return $effect;
 }
 
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
index 12d845c..f9a746c 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
@@ -258,4 +258,41 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
     $this->drupalGet('node/' . $nid);
     $this->assertRaw(image_style_url('thumbnail', file_load($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid'])->uri), t('Image displayed using style replacement style.'));
   }
+
+  /**
+   * Verify that editing an image effect does not cause it to duplicate.
+   */
+  function testEditEffect() {
+    // Add a scale effect.
+    $this->drupalGet('admin/config/media/image-styles/add');
+    $this->drupalPost(NULL, array('name' => 'test_style_effect_edit'), t('Create new style'));
+    $this->drupalPost(NULL, array('new' => 'image_scale_and_crop'), t('Add'));
+    $this->drupalPost(NULL, array('data[width]' => '300', 'data[height]' => '200'), t('Add effect'));
+    $this->assertText(t('Scale and crop 300x200'));
+
+    // There should normally be only one edit link on this page initially.
+    $this->clickLink(t('edit'));
+    $this->drupalPost(NULL, array('data[width]' => '360', 'data[height]' => '240'), t('Update effect'));
+    $this->assertText(t('Scale and crop 360x240'));
+
+    // Check the previous effect is replaced.
+    $this->assertNoText(t('Scale and crop 300x200'));
+
+    // Add another scale effect.
+    $this->drupalGet('admin/config/media/image-styles/add');
+    $this->drupalPost(NULL, array('name' => 'test_style_scale_edit_scale'), t('Create new style'));
+    $this->drupalPost(NULL, array('new' => 'image_scale'), t('Add'));
+    $this->drupalPost(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
+
+    // Edit the last added scale effect.
+    $this->clickLink(t('edit'));
+    $this->drupalPost(NULL, array('data[width]' => '24', 'data[height]' => '19'), t('Update effect'));
+    $this->drupalPost(NULL, array('new' => 'image_scale'), t('Add'));
+
+    // Add another scale effect and make sure both exists.
+    $this->drupalPost(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
+    $this->assertText(t('Scale 24x19'));
+    $this->assertText(t('Scale 12x19'));
+  }
+
 }
