Index: src/wp-admin/includes/image-edit.php
===================================================================
--- src/wp-admin/includes/image-edit.php	(revision 37861)
+++ src/wp-admin/includes/image-edit.php	(working copy)
@@ -68,7 +68,7 @@
 		</label>
 		<span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span>
 		<input id="imgedit-scale-button" type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
- 		</div>
+		</div>
 		</fieldset>
 
 		</div>
@@ -520,7 +520,7 @@
 		 * @since 3.5.0
 		 *
 		 * @param WP_Image_Editor $image   WP_Image_Editor instance.
- 		 * @param array           $changes Array of change operations.
+		 * @param array           $changes Array of change operations.
 		 */
 		$image = apply_filters( 'wp_image_editor_before_change', $image, $changes );
 	} elseif ( is_resource( $image ) ) {
@@ -532,7 +532,7 @@
 		 * @deprecated 3.5.0 Use wp_image_editor_before_change instead.
 		 *
 		 * @param resource $image   GD image resource.
- 		 * @param array    $changes Array of change operations.
+		 * @param array    $changes Array of change operations.
 		 */
 		$image = apply_filters( 'image_edit_before_change', $image, $changes );
 	}
@@ -827,6 +827,22 @@
 		$success = $delete = $nocrop = true;
 	}
 
+	/*
+	 * We need to remove any existing resized image files because
+	 * a new crop could generate different image file sizes and so
+	 * different file names, and so the new resized images won't
+	 * necessarily overwrite the existing resized image files
+	 * https://core.trac.wordpress.org/ticket/32171
+	*/
+	if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE && ! empty( $meta['sizes'] ) ) {
+		foreach ( $meta['sizes'] as $size ) {
+			if ( ! empty( $size['file'] ) && preg_match('/-e[0-9]{13}-/', $size['file'] ) ) {
+				$delete_file = path_join( dirname( $new_path ), $size['file'] );
+				wp_delete_file( $delete_file );
+			}
+		}
+	}
+
 	if ( isset( $sizes ) ) {
 		$_sizes = array();
 
Index: tests/phpunit/tests/ajax/MediaEdit.php
===================================================================
--- tests/phpunit/tests/ajax/MediaEdit.php	(revision 37861)
+++ tests/phpunit/tests/ajax/MediaEdit.php	(working copy)
@@ -51,4 +51,50 @@
 		$this->assertArrayHasKey('sizes', $media_meta, 'cropped attachment should have size data');
 		$this->assertArrayHasKey('medium', $media_meta['sizes'], 'cropped attachment should have data for medium size');
 	}
+
+	/**
+	 * @ticket 32171
+	 */
+	public function testImageEditOverwriteConstant() {
+		define( 'IMAGE_EDIT_OVERWRITE', true );
+
+		include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
+
+		$filename = DIR_TESTDATA . '/images/canola.jpg';
+		$contents = file_get_contents( $filename );
+
+		$upload = wp_upload_bits( basename( $filename ), null, $contents );
+		$id = $this->_make_attachment( $upload );
+
+		$_REQUEST['action'] = 'image-editor';
+		$_REQUEST['context'] = 'edit-attachment';
+		$_REQUEST['postid'] = $id;
+		$_REQUEST['target'] = 'all';
+		$_REQUEST['do'] = 'save';
+		$_REQUEST['history'] = '[{"c":{"x":5,"y":8,"w":289,"h":322}}]';
+
+		$ret = wp_save_image( $id );
+
+		$media_meta = wp_get_attachment_metadata( $id );
+		$sizes1 = $media_meta['sizes'];
+
+		$_REQUEST['history'] = '[{"c":{"x":5,"y":8,"w":189,"h":322}}]';
+
+		$ret = wp_save_image( $id );
+
+		$media_meta = wp_get_attachment_metadata( $id );
+		$sizes2 = $media_meta['sizes'];
+
+		$file_path = dirname( get_attached_file( $id ) );
+
+		foreach ( $sizes1 as $key => $size ) {
+			if ( $sizes2[ $key ]['file'] !== $size['file'] ) {
+				$files_that_shouldnt_exist[] = $file_path . '/' . $size['file'];
+			}
+		}
+
+		foreach ( $files_that_shouldnt_exist as $file ) {
+			$this->assertFalse( file_exists( $file ), 'IMAGE_EDIT_OVERWRITE is leaving garbage image files behind.' );
+		}
+	}
 }
