diff --git src/wp-admin/js/image-edit.js src/wp-admin/js/image-edit.js
index 9eaf51b..8e24a19 100644
--- src/wp-admin/js/image-edit.js
+++ src/wp-admin/js/image-edit.js
@@ -5,6 +5,7 @@ var imageEdit = window.imageEdit = {
 	iasapi : {},
 	hold : {},
 	postid : '',
+	_view : {},
 
 	intval : function(f) {
 		return f | 0;
@@ -241,11 +242,17 @@ var imageEdit = window.imageEdit = {
 		$.post(ajaxurl, data, function(r) {
 			$('#image-editor-' + postid).empty().append(r);
 			t.toggleEditor(postid, 0);
+			if ( t._view ) {
+				t._view.refresh();
+			}
 		});
 	},
 
 	save : function(postid, nonce) {
-		var data, target = this.getTarget(postid), history = this.filterHistory(postid, 0);
+		var data,
+			target = this.getTarget(postid),
+			history = this.filterHistory(postid, 0),
+			self = this;
 
 		if ( '' === history ) {
 			return false;
@@ -283,11 +290,17 @@ var imageEdit = window.imageEdit = {
 				$('#imgedit-response-' + postid).html('<div class="updated"><p>' + ret.msg + '</p></div>');
 			}
 
+			if ( self._view ) {
+				self._view.refresh();
+			}
+
 			imageEdit.close(postid);
 		});
 	},
 
-	open : function(postid, nonce) {
+	open : function( postid, nonce, view ) {
+		this._view = view;
+
 		var data, elem = $('#image-editor-' + postid), head = $('#media-head-' + postid),
 			btn = $('#imgedit-open-btn-' + postid), spin = btn.siblings('.spinner');
 
@@ -319,8 +332,10 @@ var imageEdit = window.imageEdit = {
 	},
 
 	initCrop : function(postid, image, parent) {
-		var t = this, selW = $('#imgedit-sel-width-' + postid),
-			selH = $('#imgedit-sel-height-' + postid);
+		var t = this,
+			selW = $('#imgedit-sel-width-' + postid),
+			selH = $('#imgedit-sel-height-' + postid),
+			$img;
 
 		t.iasapi = $(image).imgAreaSelect({
 			parent: parent,
@@ -330,7 +345,13 @@ var imageEdit = window.imageEdit = {
 			minWidth: 3,
 			minHeight: 3,
 
-			onInit: function() {
+			onInit: function( img ) {
+				// Ensure that the imgareaselect wrapper elements are position:absolute
+				// (even if we're in a position:fixed modal)
+				$img = $( img );
+				$img.next().css( 'position', 'absolute' )
+					.nextAll( '.imgareaselect-outer' ).css( 'position', 'absolute' );
+
 				parent.children().mousedown(function(e){
 					var ratio = false, sel, defRatio;
 
@@ -397,10 +418,22 @@ var imageEdit = window.imageEdit = {
 
 		this.iasapi = {};
 		this.hold = {};
-		$('#image-editor-' + postid).fadeOut('fast', function() {
-			$('#media-head-' + postid).fadeIn('fast');
-			$(this).empty();
-		});
+
+		// If we've loaded the editor in the context of a Media Modal, then switch to the previous view,
+		// whatever that might have been.
+		if ( this._view && 'object' === typeof this._view ){
+			this._view.back();
+		}
+
+		// In case we are not accessing the image editor in the context of a View, close the editor the old-skool way
+		else {
+			$('#image-editor-' + postid).fadeOut('fast', function() {
+				$('#media-head-' + postid).fadeIn('fast');
+				$(this).empty();
+			});
+		}
+
+
 	},
 
 	notsaved : function(postid) {
diff --git src/wp-includes/js/media-editor.js src/wp-includes/js/media-editor.js
index ec13796..b2dfd15 100644
--- src/wp-includes/js/media-editor.js
+++ src/wp-includes/js/media-editor.js
@@ -648,7 +648,7 @@
 
 			this._frame = wp.media({
 				state: 'featured-image',
-				states: [ new wp.media.controller.FeaturedImage() ]
+				states: [ new wp.media.controller.FeaturedImage() , new wp.media.controller.EditImage() ]
 			});
 
 			this._frame.on( 'toolbar:create:featured-image', function( toolbar ) {
@@ -660,6 +660,17 @@
 				});
 			}, this._frame );
 
+			this._frame.on( 'content:render:edit-image', function() {
+				var selection = this.state('featured-image').get('selection'),
+					view = new wp.media.view.EditImage( { model: selection.single(), controller: this } ).render();
+
+				this.content.set( view );
+
+				// after bringing in the frame, load the actual editor via an ajax call
+				view.loadEditor();
+
+			}, this._frame );
+
 			this._frame.state('featured-image').on( 'select', this.select );
 			return this._frame;
 		},
diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js
index 5363ffe..2580793 100644
--- src/wp-includes/js/media-models.js
+++ src/wp-includes/js/media-models.js
@@ -367,6 +367,7 @@ window.wp = window.wp || {};
 
 		bindAttachmentListeners: function() {
 			this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
+			this.listenTo( this.attachment, 'change', this.updateSize );
 		},
 
 		changeAttachment: function( attachment, props ) {
diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js
index db5ea30..5a48476 100644
--- src/wp-includes/js/media-views.js
+++ src/wp-includes/js/media-views.js
@@ -482,6 +482,54 @@
 		};
 	});
 
+	media.selectionSync = {
+		syncSelection: function() {
+			var selection = this.get('selection'),
+				manager = this.frame._selection;
+
+			if ( ! this.get('syncSelection') || ! manager || ! selection ) {
+				return;
+			}
+
+			// If the selection supports multiple items, validate the stored
+			// attachments based on the new selection's conditions. Record
+			// the attachments that are not included; we'll maintain a
+			// reference to those. Other attachments are considered in flux.
+			if ( selection.multiple ) {
+				selection.reset( [], { silent: true });
+				selection.validateAll( manager.attachments );
+				manager.difference = _.difference( manager.attachments.models, selection.models );
+			}
+
+			// Sync the selection's single item with the master.
+			selection.single( manager.single );
+		},
+
+		/**
+		 * Record the currently active attachments, which is a combination
+		 * of the selection's attachments and the set of selected
+		 * attachments that this specific selection considered invalid.
+		 * Reset the difference and record the single attachment.
+		 */
+		recordSelection: function() {
+			var selection = this.get('selection'),
+				manager = this.frame._selection;
+
+			if ( ! this.get('syncSelection') || ! manager || ! selection ) {
+				return;
+			}
+
+			if ( selection.multiple ) {
+				manager.attachments.reset( selection.toArray().concat( manager.difference ) );
+				manager.difference = [];
+			} else {
+				manager.attachments.add( selection.toArray() );
+			}
+
+			manager.single = selection._single;
+		}
+	};
+
 	/**
 	 * wp.media.controller.Library
 	 *
@@ -634,51 +682,6 @@
 			return _.contains( media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
 		},
 
-		syncSelection: function() {
-			var selection = this.get('selection'),
-				manager = this.frame._selection;
-
-			if ( ! this.get('syncSelection') || ! manager || ! selection ) {
-				return;
-			}
-
-			// If the selection supports multiple items, validate the stored
-			// attachments based on the new selection's conditions. Record
-			// the attachments that are not included; we'll maintain a
-			// reference to those. Other attachments are considered in flux.
-			if ( selection.multiple ) {
-				selection.reset( [], { silent: true });
-				selection.validateAll( manager.attachments );
-				manager.difference = _.difference( manager.attachments.models, selection.models );
-			}
-
-			// Sync the selection's single item with the master.
-			selection.single( manager.single );
-		},
-
-		/**
-		 * Record the currently active attachments, which is a combination
-		 * of the selection's attachments and the set of selected
-		 * attachments that this specific selection considered invalid.
-		 * Reset the difference and record the single attachment.
-		 */
-		recordSelection: function() {
-			var selection = this.get('selection'),
-				manager = this.frame._selection;
-
-			if ( ! this.get('syncSelection') || ! manager || ! selection ) {
-				return;
-			}
-
-			if ( selection.multiple ) {
-				manager.attachments.reset( selection.toArray().concat( manager.difference ) );
-				manager.difference = [];
-			} else {
-				manager.attachments.add( selection.toArray() );
-			}
-
-			manager.single = selection._single;
-		},
 
 		/**
 		 * If the state is active, no items are selected, and the current
@@ -733,6 +736,8 @@
 		}
 	});
 
+	_.extend( media.controller.Library.prototype, media.selectionSync );
+
 	/**
 	 * wp.media.controller.ImageDetails
 	 *
@@ -1000,7 +1005,7 @@
 			toolbar:    'featured-image',
 			title:      l10n.setFeaturedImageTitle,
 			priority:   60,
-			syncSelection: false
+			syncSelection: true
 		}, media.controller.Library.prototype.defaults ),
 
 		initialize: function() {
@@ -1081,7 +1086,7 @@
 			toolbar:    'replace',
 			title:      l10n.replaceImageTitle,
 			priority:   60,
-			syncSelection: false
+			syncSelection: true
 		}, media.controller.Library.prototype.defaults ),
 
 		initialize: function( options ) {
@@ -1132,6 +1137,34 @@
 	});
 
 	/**
+	 * wp.media.controller.EditImage
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.EditImage = media.controller.State.extend({
+		defaults: {
+			id: 'edit-image',
+			url: '',
+			menu: false,
+			title: l10n.editImage,
+			content: 'edit-image',
+			syncSelection: true
+		},
+
+		activate: function() {
+			if ( ! this.get('selection') ) {
+				this.set( 'selection', new media.model.Selection() );
+			}
+			this.syncSelection();
+		}
+	});
+
+	_.extend( media.controller.EditImage.prototype, media.selectionSync );
+
+
+	/**
 	 * wp.media.controller.Embed
 	 *
 	 * @constructor
@@ -1803,6 +1836,8 @@
 				// Embed states.
 				new media.controller.Embed(),
 
+				new media.controller.EditImage( { selection: options.selection } ),
+
 				// Gallery states.
 				new media.controller.GalleryEdit({
 					library: options.selection,
@@ -1890,6 +1925,7 @@
 
 				content: {
 					'embed':          'embedContent',
+					'edit-image':     'editImageContent',
 					'edit-selection': 'editSelectionContent'
 				},
 
@@ -2040,6 +2076,17 @@
 			this.content.set( view );
 		},
 
+		editImageContent: function() {
+			var selection = this.state().get('selection'),
+				view = new media.view.EditImage( { model: selection.single(), controller: this } ).render();
+
+			this.content.set( view );
+
+			// after bringing in the frame, load the actual editor via an ajax call
+			view.loadEditor();
+
+		},
+
 		// Toolbars
 
 		/**
@@ -2370,6 +2417,7 @@
 			media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
 			this.on( 'menu:create:image-details', this.createMenu, this );
 			this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
+			this.on( 'content:render:edit-image', this.editImageContent, this );
 			this.on( 'menu:render:image-details', this.renderMenu, this );
 			this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
 			// override the select toolbar
@@ -2387,13 +2435,15 @@
 					id: 'replace-image',
 					library:   media.query( { type: 'image' } ),
 					image: this.image,
+					selection: this.options.selection,
 					multiple:  false,
 					title:     l10n.imageReplaceTitle,
 					menu: 'image-details',
 					toolbar: 'replace',
 					priority:  80,
 					displaySettings: true
-				})
+				}),
+				new media.controller.EditImage( { image: this.image, selection: this.options.selection } )
 			]);
 		},
 
@@ -2433,6 +2483,31 @@
 
 		},
 
+		editImageContent: function() {
+			var state = this.state(),
+				attachment = state.get('image').attachment,
+				model,
+				view;
+
+			if ( ! attachment ) {
+				return;
+			}
+
+			model = state.get('selection').single();
+
+			if ( ! model ) {
+				model = attachment;
+			}
+
+			view = new media.view.EditImage( { model: model, controller: this } ).render();
+
+			this.content.set( view );
+
+			// after bringing in the frame, load the actual editor via an ajax call
+			view.loadEditor();
+
+		},
+
 		renderImageDetailsToolbar: function() {
 			this.toolbar.set( new media.view.Toolbar({
 				controller: this,
@@ -5250,8 +5325,9 @@
 			}
 		},
 
-		editAttachment: function() {
-			this.$el.addClass('needs-refresh');
+		editAttachment: function( event ) {
+			event.preventDefault();
+			this.controller.setState( 'edit-image' );
 		},
 		/**
 		 * @param {Object} event
@@ -5261,6 +5337,7 @@
 			event.preventDefault();
 			this.model.fetch();
 		}
+
 	});
 
 	/**
@@ -5534,10 +5611,15 @@
 	media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
 		className: 'image-details',
 		template:  media.template('image-details'),
-
+		events: _.defaults( media.view.Settings.AttachmentDisplay.prototype.events, {
+			'click .edit-attachment': 'editAttachment'
+		} ),
 		initialize: function() {
 			// used in AttachmentDisplay.prototype.updateLinkTo
 			this.options.attachment = this.model.attachment;
+			if ( this.model.attachment ) {
+				this.listenTo( this.model.attachment, 'change:url', this.updateUrl );
+			}
 			media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
 		},
 
@@ -5553,7 +5635,6 @@
 			}, this.options );
 		},
 
-
 		render: function() {
 			var self = this,
 				args = arguments;
@@ -5574,6 +5655,53 @@
 		resetFocus: function() {
 			this.$( '.caption textarea' ).focus();
 			this.$( '.embed-image-settings' ).scrollTop( 0 );
+		},
+
+		updateUrl: function() {
+			this.$( '.thumbnail img' ).attr( 'src', this.model.get('url' ) );
+			this.$( '.url' ).val( this.model.get('url' ) );
+		},
+
+		editAttachment: function( event ) {
+			event.preventDefault();
+			this.controller.setState( 'edit-image' );
 		}
 	});
+
+
+	media.view.EditImage = media.View.extend({
+
+		className: 'image-editor',
+		template: media.template('image-editor'),
+
+		initialize: function( options ) {
+			this.editor = window.imageEdit;
+			this.controller = options.controller;
+			media.View.prototype.initialize.apply( this, arguments );
+		},
+
+		prepare: function() {
+			return this.model.toJSON();
+		},
+
+		render: function() {
+			media.View.prototype.render.apply( this, arguments );
+			return this;
+		},
+
+		loadEditor: function() {
+			this.editor.open( this.model.get('id'), this.model.get('nonces').edit, this );
+		},
+
+		back: function() {
+			var lastState = this.controller.lastState();
+			this.controller.setState( lastState );
+		},
+
+		refresh: function() {
+			this.model.fetch();
+		}
+
+	});
+
 }(jQuery));
diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
index daf8c29..752502c 100644
--- src/wp-includes/media-template.php
+++ src/wp-includes/media-template.php
@@ -560,6 +560,9 @@ function wp_print_media_templates() {
 				<div class="thumbnail">
 					<img src="{{ data.model.url }}" draggable="false" />
 				</div>
+				<# if ( data.attachment ) { #>
+					<input type="button" class="edit-attachment button" value="<?php esc_attr_e( 'Edit Image' ); ?>" />
+				<# } #>
 
 				<div class="setting url">
 					<?php // might want to make the url editable if it isn't an attachment ?>
@@ -649,6 +652,11 @@ function wp_print_media_templates() {
 			</div>
 		</div>
 	</script>
+
+	<script type="text/html" id="tmpl-image-editor">
+		<div id="media-head-{{{ data.id }}}"></div>
+		<div id="image-editor-{{{ data.id }}}"></div>
+	</script>
 	<?php
 
 	/**
diff --git src/wp-includes/media.php src/wp-includes/media.php
index ebcfa0e..6b09bc3 100644
--- src/wp-includes/media.php
+++ src/wp-includes/media.php
@@ -2135,12 +2135,14 @@ function wp_prepare_attachment_for_js( $attachment ) {
 		'nonces'      => array(
 			'update' => false,
 			'delete' => false,
+			'edit'   => false
 		),
 		'editLink'   => false,
 	);
 
 	if ( current_user_can( 'edit_post', $attachment->ID ) ) {
 		$response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
+		$response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
 		$response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
 	}
 
@@ -2340,6 +2342,7 @@ function wp_enqueue_media( $args = array() ) {
 		'imageDetailsTitle'     => __( 'Image Details' ),
 		'imageReplaceTitle'     => __( 'Replace Image' ),
 		'imageDetailsCancel'    => __( 'Cancel Edit' ),
+		'editImage'             => __( 'Edit Image' ),
 
  		// Playlist
  		'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
@@ -2371,6 +2374,7 @@ function wp_enqueue_media( $args = array() ) {
 
 	wp_enqueue_script( 'media-editor' );
 	wp_enqueue_style( 'media-views' );
+	wp_enqueue_style( 'imgareaselect' );
 	wp_plupload_default_settings();
 
 	require_once ABSPATH . WPINC . '/media-template.php';
@@ -2590,4 +2594,4 @@ function theme_supports_thumbnails( $post ) {
 	}
 
 	return current_theme_supports( 'post-thumbnails', $post->post_type );
-}
\ No newline at end of file
+}
diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
index d696b13..a3dc3b7 100644
--- src/wp-includes/script-loader.php
+++ src/wp-includes/script-loader.php
@@ -395,7 +395,7 @@ function wp_default_scripts( &$scripts ) {
 	// To enqueue media-views or media-editor, call wp_enqueue_media().
 	// Both rely on numerous settings, styles, and templates to operate correctly.
 	$scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable' ), false, 1 );
-	$scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
+	$scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views', 'image-edit' ), false, 1 );
 	$scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
 
 	if ( is_admin() ) {
