Index: wp-admin/includes/ajax-actions.php
===================================================================
--- wp-admin/includes/ajax-actions.php	(revision 22962)
+++ wp-admin/includes/ajax-actions.php	(working copy)
@@ -1674,23 +1674,31 @@
 }
 
 function wp_ajax_set_post_thumbnail() {
+	$json = ! empty( $_REQUEST['json'] );
+
 	$post_ID = intval( $_POST['post_id'] );
-	if ( !current_user_can( 'edit_post', $post_ID ) )
-		wp_die( -1 );
+	if ( !current_user_can( 'edit_post', $post_ID ) ) {
+		$json ? wp_send_json_error() : wp_die( -1 );
+	}
 	$thumbnail_id = intval( $_POST['thumbnail_id'] );
 
 	check_ajax_referer( "set_post_thumbnail-$post_ID" );
 
 	if ( $thumbnail_id == '-1' ) {
-		if ( delete_post_thumbnail( $post_ID ) )
-			wp_die( _wp_post_thumbnail_html( null, $post_ID ) );
-		else
-			wp_die( 0 );
+		if ( delete_post_thumbnail( $post_ID ) ) {
+			$return = _wp_post_thumbnail_html( null, $post_ID );
+			$json ? wp_send_json_success( $return ) : wp_die( $json );
+		} else {
+			$json ? wp_send_json_error() : wp_die( 0 );
+		}
 	}
 
-	if ( set_post_thumbnail( $post_ID, $thumbnail_id ) )
-		wp_die( _wp_post_thumbnail_html( $thumbnail_id, $post_ID ) );
-	wp_die( 0 );
+	if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
+		$return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
+		$json ? wp_send_json_success( $return ) : wp_die( $json );
+	}
+
+	$json ? wp_send_json_error() : wp_die( 0 );
 }
 
 function wp_ajax_date_format() {
Index: wp-admin/includes/meta-boxes.php
===================================================================
--- wp-admin/includes/meta-boxes.php	(revision 22962)
+++ wp-admin/includes/meta-boxes.php	(working copy)
@@ -1001,119 +1001,6 @@
  * @since 2.9.0
  */
 function post_thumbnail_meta_box( $post ) {
-	global $_wp_additional_image_sizes;
-
-	?><script type="text/javascript">
-	jQuery( function($) {
-		var $element     = $('#select-featured-image'),
-			$thumbnailId = $element.find('input[name="thumbnail_id"]'),
-			title        = '<?php _e( "Choose a Featured Image" ); ?>',
-			update       = '<?php _e( "Update Featured Image" ); ?>',
-			Attachment   = wp.media.model.Attachment,
-			frame, setFeaturedImage;
-
-		setFeaturedImage = function( thumbnailId ) {
-			var selection;
-
-			$element.find('img').remove();
-			$element.toggleClass( 'has-featured-image', -1 != thumbnailId );
-			$thumbnailId.val( thumbnailId );
-
-			if ( frame ) {
-				selection = frame.state('library').get('selection');
-
-				if ( -1 === thumbnailId )
-					selection.clear();
-				else
-					selection.add( Attachment.get( thumbnailId ) );
-			}
-		};
-
-		$element.on( 'click', '.choose, img', function( event ) {
-			var options, thumbnailId, attachment;
-
-			event.preventDefault();
-
-			if ( frame ) {
-				frame.open();
-				return;
-			}
-
-			options = {
-				title:   title,
-				library: {
-					type: 'image'
-				}
-			};
-
-			thumbnailId = $thumbnailId.val();
-			if ( '' !== thumbnailId && -1 !== thumbnailId ) {
-				attachment = Attachment.get( thumbnailId );
-				attachment.fetch();
-				options.selection = [ attachment ];
-			}
-
-			frame = wp.media( options );
-
-			frame.state('library').set( 'filterable', 'uploaded' );
-
-			frame.toolbar.on( 'activate:select', function() {
-				frame.toolbar.view().set({
-					select: {
-						style: 'primary',
-						text:  update,
-
-						click: function() {
-							var selection = frame.state().get('selection'),
-								model = selection.first(),
-								sizes = model.get('sizes'),
-								size;
-
-							setFeaturedImage( model.id );
-
-							// @todo: might need a size hierarchy equivalent.
-							if ( sizes )
-								size = sizes['post-thumbnail'] || sizes.medium;
-
-							// @todo: Need a better way of accessing full size
-							// data besides just calling toJSON().
-							size = size || model.toJSON();
-
-							frame.close();
-
-							$( '<img />', {
-								src:    size.url,
-								width:  size.width
-							}).prependTo( $element );
-						}
-					}
-				});
-			});
-
-			frame.toolbar.mode('select');
-		});
-
-		$element.on( 'click', '.remove', function( event ) {
-			event.preventDefault();
-			setFeaturedImage( -1 );
-		});
-	});
-	</script>
-
-	<?php
-	$thumbnail_id   = get_post_meta( $post->ID, '_thumbnail_id', true );
-	$thumbnail_size = isset( $_wp_additional_image_sizes['post-thumbnail'] ) ? 'post-thumbnail' : 'medium';
-	$thumbnail_html = wp_get_attachment_image( $thumbnail_id, $thumbnail_size );
-
-	$classes = empty( $thumbnail_id ) ? '' : 'has-featured-image';
-
-	?><div id="select-featured-image"
-		class="<?php echo esc_attr( $classes ); ?>"
-		data-post-id="<?php echo esc_attr( $post->ID ); ?>">
-		<?php echo $thumbnail_html; ?>
-		<input type="hidden" name="thumbnail_id" value="<?php echo esc_attr( $thumbnail_id ); ?>" />
-		<a href="#" class="choose button-secondary"><?php _e( 'Choose a Featured Image' ); ?></a>
-		<a href="#" class="remove"><?php _e( 'Remove Featured Image' ); ?></a>
-	</div>
-	<?php
+	$thumbnail_id = get_post_meta( $post->ID, '_thumbnail_id', true );
+	echo _wp_post_thumbnail_html( $thumbnail_id, $post->ID );
 }
\ No newline at end of file
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 22962)
+++ wp-admin/includes/post.php	(working copy)
@@ -199,14 +199,6 @@
 			set_post_format( $post_ID, false );
 	}
 
-	// Featured Images
-	if ( isset( $post_data['thumbnail_id'] ) ) {
-		if ( '-1' == $post_data['thumbnail_id'] )
-			delete_post_thumbnail( $post_ID );
-		else
-			set_post_thumbnail( $post_ID, $post_data['thumbnail_id'] );
-	}
-
 	// Meta Stuff
 	if ( isset($post_data['meta']) && $post_data['meta'] ) {
 		foreach ( $post_data['meta'] as $key => $value ) {
Index: wp-admin/js/custom-background.js
===================================================================
--- wp-admin/js/custom-background.js	(revision 22962)
+++ wp-admin/js/custom-background.js	(working copy)
@@ -57,7 +57,7 @@
 				});
 			});
 
-			frame.setState('library');
+			frame.setState('library').open();
 		});
 	});
 })(jQuery);
\ No newline at end of file
Index: wp-admin/js/custom-header.js
===================================================================
--- wp-admin/js/custom-header.js	(revision 22962)
+++ wp-admin/js/custom-header.js	(working copy)
@@ -40,7 +40,7 @@
 				});
 			});
 
-			frame.setState('library');
+			frame.setState('library').open();
 		});
 	});
 }(jQuery));
Index: wp-includes/css/media-views.css
===================================================================
--- wp-includes/css/media-views.css	(revision 22962)
+++ wp-includes/css/media-views.css	(working copy)
@@ -403,6 +403,11 @@
  */
 .media-frame {
 	overflow: hidden;
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
 }
 
 .media-frame .region-content {
Index: wp-includes/js/media-editor.js
===================================================================
--- wp-includes/js/media-editor.js	(revision 22962)
+++ wp-includes/js/media-editor.js	(working copy)
@@ -375,6 +375,7 @@
 
 			workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
 				frame:    'post',
+				state:    'upload',
 				title:    wp.media.view.l10n.addMedia,
 				multiple: true
 			} ) );
@@ -427,14 +428,53 @@
 				}
 			}, this );
 
+			workflow.state('featured-image').on( 'select', function() {
+				var settings = wp.media.view.settings,
+					featuredImage = settings.featuredImage,
+					selection = this.get('selection').single();
+
+				if ( ! featuredImage )
+					return;
+
+				featuredImage.id = selection ? selection.id : -1;
+				wp.media.post( 'set-post-thumbnail', {
+					json:         true,
+					post_id:      settings.postId,
+					thumbnail_id: featuredImage.id,
+					_wpnonce:     featuredImage.nonce
+				}).done( function( html ) {
+					$( '.inside', '#postimagediv' ).html( html );
+					$('#set-post-thumbnail').removeClass('thickbox');
+				});
+			});
+
+			workflow.setState( workflow.options.state );
 			return workflow;
 		},
 
+		id: function( id ) {
+			if ( id )
+				return id;
+
+			// If an empty `id` is provided, default to `wpActiveEditor`.
+			id = wpActiveEditor;
+
+			// If that doesn't work, fall back to `tinymce.activeEditor.id`.
+			if ( ! id && typeof tinymce !== 'undefined' && tinymce.activeEditor )
+				id = tinymce.activeEditor.id;
+
+			// Last but not least, fall back to the empty string.
+			id = id || '';
+			return id;
+		},
+
 		get: function( id ) {
+			id = this.id( id );
 			return workflows[ id ];
 		},
 
 		remove: function( id ) {
+			id = this.id( id );
 			delete workflows[ id ];
 		},
 
@@ -497,6 +537,30 @@
 			}
 		},
 
+		open: function( id ) {
+			var workflow, editor;
+
+			id = this.id( id );
+
+			// Save a bookmark of the caret position in IE.
+			if ( typeof tinymce !== 'undefined' ) {
+				editor = tinymce.get( id );
+
+				if ( tinymce.isIE && editor && ! editor.isHidden() ) {
+					editor.focus();
+					editor.windowManager.insertimagebookmark = editor.selection.getBookmark();
+				}
+			}
+
+			workflow = this.get( id );
+
+			// Initialize the editor's workflow if we haven't yet.
+			if ( ! workflow )
+				workflow = this.add( id );
+
+			return workflow.open();
+		},
+
 		init: function() {
 			$(document.body).on( 'click', '.insert-media', function( event ) {
 				var $this = $(this),
@@ -513,45 +577,33 @@
 
 				wp.media.editor.open( editor );
 			});
-		},
 
-		open: function( id ) {
-			var workflow, editor;
+			// Initialize post thumbnails.
+			$('#set-post-thumbnail').removeClass('thickbox');
+			$('#postimagediv').on( 'click', '#set-post-thumbnail', function( event ) {
+				event.preventDefault();
 
-			// If an empty `id` is provided, default to `wpActiveEditor`.
-			id = id || wpActiveEditor;
+				// Always get the 'content' frame, since this is tailored to post.php.
+				var frame = wp.media.editor.get('content') || wp.media.editor.add('content'),
+					id = wp.media.view.settings.featuredImage.id,
+					model = wp.media.model,
+					selection = [],
+					attachment;
 
-			if ( typeof tinymce !== 'undefined' && tinymce.activeEditor ) {
-				// If that doesn't work, fall back to `tinymce.activeEditor`.
-				if ( ! id ) {
-					editor = tinymce.activeEditor;
-					id = id || editor.id;
-				} else {
-					editor = tinymce.get( id );
+				if ( '' !== id && -1 !== id ) {
+					attachment = model.Attachment.get( id );
+					attachment.fetch();
+					selection.push( attachment );
 				}
 
-				// Save a bookmark of the caret position, needed for IE
-				if ( tinymce.isIE && editor && ! editor.isHidden() ) {
-					editor.focus();
-					editor.windowManager.insertimagebookmark = editor.selection.getBookmark();
-				}
-			}
+				selection = new model.Selection( selection );
 
-			// Last but not least, fall back to the empty string.
-			id = id || '';
-
-			workflow = wp.media.editor.get( id );
-
-			// If the workflow exists, open it.
-			// Initialize the editor's workflow if we haven't yet.
-			if ( workflow )
-				workflow.open();
-			else
-				workflow = wp.media.editor.add( id );
-
-			return workflow;
+				frame.state('featured-image').set( 'selection', selection );
+				frame.setState('featured-image').open();
+			});
 		}
 	};
 
+	_.bindAll( wp.media.editor, 'open' );
 	$( wp.media.editor.init );
 }(jQuery));
Index: wp-includes/js/media-models.js
===================================================================
--- wp-includes/js/media-models.js	(revision 22962)
+++ wp-includes/js/media-models.js	(working copy)
@@ -30,10 +30,8 @@
 			frame = new MediaFrame.Post( attributes );
 
 		delete attributes.frame;
-		// Set the default state.
-		frame.setState( frame.options.state );
-		// Render, attach, and open the frame.
-		return frame.render().attach().open();
+
+		return frame;
 	};
 
 	_.extend( media, { model: {}, view: {}, controller: {} });
@@ -235,6 +233,9 @@
 
 			// Overload the `update` request so properties can be saved.
 			} else if ( 'update' === method ) {
+				if ( ! this.get('nonces') )
+					return $.Deferred().resolveWith( this ).promise();
+
 				options = options || {};
 				options.context = this;
 
Index: wp-includes/js/media-views.js
===================================================================
--- wp-includes/js/media-views.js	(revision 22962)
+++ wp-includes/js/media-views.js	(working copy)
@@ -169,7 +169,7 @@
 			// created the `states` collection, or are trying to select a state
 			// that does not exist.
 			if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) )
-				return;
+				return this;
 
 			if ( previous ) {
 				previous.trigger('deactivate');
@@ -178,6 +178,8 @@
 
 			this._state = id;
 			this.state().trigger('activate');
+
+			return this;
 		},
 
 		// Returns the previous active state.
@@ -1075,9 +1077,10 @@
 			if ( this.options.modal ) {
 				this.modal = new media.view.Modal({
 					controller: this,
-					$content:   this.$el,
 					title:      this.options.title
 				});
+
+				this.modal.content( this );
 			}
 
 			// Force the uploader off if the upload limit has been exceeded or
@@ -1100,14 +1103,6 @@
 			this.on( 'attach', _.bind( this.views.ready, this.views ), this );
 		},
 
-		render: function() {
-			if ( this.modal )
-				this.modal.render();
-
-			media.view.Frame.prototype.render.apply( this, arguments );
-			return this;
-		},
-
 		createIframeStates: function( options ) {
 			var settings = media.view.settings,
 				tabs = settings.tabs,
@@ -1200,7 +1195,6 @@
 			media.view.MediaFrame.prototype.initialize.apply( this, arguments );
 
 			_.defaults( this.options, {
-				state:     'upload',
 				selection: [],
 				library:   {},
 				multiple:  false
@@ -1347,7 +1341,6 @@
 	media.view.MediaFrame.Post = media.view.MediaFrame.Select.extend({
 		initialize: function() {
 			_.defaults( this.options, {
-				state:     'upload',
 				multiple:  true,
 				editing:   false
 			});
@@ -1407,6 +1400,18 @@
 					libraryState: 'gallery-edit'
 				})
 			]);
+
+
+			if ( media.view.settings.featuredImage ) {
+				this.states.add( new media.controller.Library({
+					id:         'featured-image',
+					library:    media.query({ type: 'image' }),
+					filterable: 'uploaded',
+					multiple:   false,
+					menu:       'main',
+					toolbar:    'featured-image'
+				}) );
+			}
 		},
 
 		bindHandlers: function() {
@@ -1425,6 +1430,7 @@
 					toolbar: {
 						'main-attachments': 'mainAttachmentsToolbar',
 						'main-embed':       'mainEmbedToolbar',
+						'featured-image':   'featuredImageToolbar',
 						'gallery-edit':     'galleryEditToolbar',
 						'gallery-add':      'galleryAddToolbar'
 					}
@@ -1442,15 +1448,22 @@
 			media.view.MediaFrame.Select.prototype.mainMenu.call( this, { silent: true });
 
 			this.menu.view().set({
-				separateLibrary: new media.View({
+				'library-separator': new media.View({
 					className: 'separator',
 					priority: 60
 				}),
-				embed: {
+				'embed': {
 					text: l10n.fromUrlTitle,
 					priority: 80
 				}
 			});
+
+			if ( media.view.settings.featuredImage ) {
+				this.menu.view().set( 'featured-image', {
+					text: l10n.featuredImageTitle,
+					priority: 100
+				});
+			}
 		},
 
 		galleryMenu: function() {
@@ -1557,6 +1570,13 @@
 			}) );
 		},
 
+		featuredImageToolbar: function() {
+			this.toolbar.view( new media.view.Toolbar.Select({
+				controller: this,
+				text:       l10n.setFeaturedImage
+			}) );
+		},
+
 		mainEmbedToolbar: function() {
 			this.toolbar.view( new media.view.Toolbar.Embed({
 				controller: this
@@ -1641,39 +1661,52 @@
 			});
 		},
 
-		render: function() {
-			// Ensure content div exists.
-			this.options.$content = this.options.$content || $('<div />');
-
-			// Detach the content element from the DOM to prevent
-			// `this.$el.html()` from garbage collecting its events.
-			this.options.$content.detach();
-
-			this.$el.html( this.template({
+		prepare: function() {
+			return {
 				title: this.options.title
-			}) );
-
-			this.options.$content.addClass('media-modal-content');
-			this.$('.media-modal').append( this.options.$content );
-			return this;
+			};
 		},
 
 		attach: function() {
+			if ( this.views.attached )
+				return;
+
+			if ( ! this.views.rendered )
+				this.render();
+
 			this.$el.appendTo( this.options.container );
+
+			// Manually mark the view as attached and trigger ready.
+			this.views.attached = true;
+			this.views.ready();
+
 			return this.propagate('attach');
 		},
 
 		detach: function() {
+			if ( this.$el.is(':visible') )
+				this.close();
+
 			this.$el.detach();
+			this.views.attached = false;
 			return this.propagate('detach');
 		},
 
 		open: function() {
+			if ( this.$el.is(':visible') )
+				return;
+
+			if ( ! this.views.attached )
+				this.attach();
+
 			this.$el.show().focus();
 			return this.propagate('open');
 		},
 
 		close: function() {
+			if ( ! this.views.attached || ! this.$el.is(':visible') )
+				return;
+
 			this.$el.hide();
 			return this.propagate('close');
 		},
@@ -1683,14 +1716,9 @@
 			this.close();
 		},
 
-		content: function( $content ) {
-			// Detach any existing content to prevent events from being lost.
-			if ( this.options.$content )
-				this.options.$content.detach();
-
-			// Set and render the content.
-			this.options.$content = ( $content instanceof Backbone.View ) ? $content.$el : $content;
-			return this.render();
+		content: function( content ) {
+			this.views.set( '.media-modal-content', content );
+			return this;
 		},
 
 		// Triggers a modal event and if the `propagate` option is set,
Index: wp-includes/media.php
===================================================================
--- wp-includes/media.php	(revision 22962)
+++ wp-includes/media.php	(working copy)
@@ -1433,6 +1433,16 @@
 	if ( isset( $args['post'] ) ) {
 		$post = get_post( $args['post'] );
 		$settings['postId'] = $post->ID;
+
+		if ( current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' ) ) {
+
+			$featuredImageId = get_post_meta( $post->ID, '_thumbnail_id', true );
+
+			$settings['featuredImage'] = array(
+				'id'    => $featuredImageId ? $featuredImageId : -1,
+				'nonce' => wp_create_nonce( 'set_post_thumbnail-' . $post->ID ),
+			);
+		}
 	}
 
 	$hier = $post && is_post_type_hierarchical( $post->post_type );
@@ -1466,6 +1476,10 @@
 		// From URL
 		'fromUrlTitle'       => __( 'From URL' ),
 
+		// Featured Images
+		'featuredImageTitle'  => __( 'Featured Image' ),
+		'setFeaturedImage'    => __( 'Set featured image' ),
+
 		// Gallery
 		'createGalleryTitle' => __( 'Create Gallery' ),
 		'editGalleryTitle'   => __( 'Edit Gallery' ),
@@ -1508,6 +1522,7 @@
 		<div class="media-modal wp-core-ui">
 			<h3 class="media-modal-title">{{ data.title }}</h3>
 			<a class="media-modal-close media-modal-icon" href="#" title="<?php esc_attr_e('Close'); ?>"></a>
+			<div class="media-modal-content"></div>
 		</div>
 		<div class="media-modal-backdrop">
 			<div></div>
