diff --git src/bp-core/bp-core-attachments.php src/bp-core/bp-core-attachments.php
index 1fadb11..a652386 100644
--- src/bp-core/bp-core-attachments.php
+++ src/bp-core/bp-core-attachments.php
@@ -257,6 +257,36 @@ function bp_attachments_enqueue_scripts( $class = '' ) {
 		 * @param string $object the object the avatar belongs to (eg: user or group)
 		 */
 		$settings['nav'] = bp_sort_by_key( apply_filters( 'bp_attachments_avatar_nav', $avatar_nav, $object ), 'order', 'num' );
+
+	// Specific to BuddyPress cover images
+	} elseif ( 'bp_cover_image_upload' === $defaults['multipart_params']['action'] ) {
+
+		// Cover images only need 1 file and 1 only!
+		$defaults['multi_selection'] = false;
+
+		// Default cover component is xprofile
+		$cover_component = 'xprofile';
+
+		// Get the object we're editing the cover image of
+		$object = $defaults['multipart_params']['bp_params']['object'];
+
+		// Set the cover component according to the object
+		if ( 'group' === $object ) {
+			$cover_component = 'groups';
+		} elseif ( 'user' !== $object ) {
+			$cover_component = apply_filters( 'bp_attachments_cover_image_ui_component', $cover_component );
+		}
+		// Get cover image advised dimensions
+		$cover_dimensions = bp_attachments_get_cover_image_dimensions( $cover_component );
+
+		// Set warning messages
+		$strings['cover_image_warnings'] = apply_filters( 'bp_attachments_cover_image_ui_warnings', array(
+			'dimensions'  => sprintf(
+					__( 'For better results, make sure to upload an image having a width >= %1$s px and a height >= %2$s px.', 'buddypress' ),
+					(int) $cover_dimensions['width'],
+					(int) $cover_dimensions['height']
+				),
+		) );
 	}
 
 	// Set Plupload settings
@@ -317,7 +347,7 @@ function bp_attachments_enqueue_scripts( $class = '' ) {
 function bp_attachments_current_user_can( $capability, $args = array() ) {
 	$can = false;
 
-	if ( 'edit_avatar' === $capability ) {
+	if ( 'edit_avatar' === $capability || 'edit_cover_image' === $capability ) {
 		/**
 		 * Needed avatar arguments are set.
 		 */
@@ -410,3 +440,479 @@ function bp_attachments_get_template_part( $slug ) {
 		bp_get_template_part( $attachment_template_part );
 	}
 }
+
+/** Cover Image ***************************************************************/
+
+/**
+ * Get the cover image settings
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  string $component the component to get the settings for ("xprofile" for user or "groups")
+ * @return array            the cover image settings
+ */
+function bp_attachments_get_cover_image_settings( $component = 'xprofile' ) {
+	// Default parameters
+	$args = array();
+
+	// First look in BP Theme Compat
+	$cover_image = bp_get_theme_compat_feature( 'cover_image' );
+
+	if ( ! empty( $cover_image ) ) {
+		$args = (array) $cover_image;
+	}
+
+	/**
+	 * Then let people override/set the feature using this dynamic filter
+	 *
+	 * eg: for the user's profile cover image use :
+	 * add_filter( 'bp_before_xprofile_cover_image_settings_parse_args', 'your_filter', 10, 1 );
+	 *
+	 * @since  BuddyPress (2.4.0)
+	 *
+	 * @param array $settings the cover image settings
+	 */
+	$settings = bp_parse_args( $args, array(
+		'components'    => array(),
+		'width'         => 1300,
+		'height'        => 225,
+		'callback'      => '',
+		'theme_handle'  => '',
+		'default_cover' => '',
+	), $component . '_cover_image_settings' );
+
+	if ( empty( $settings['components'] ) || empty( $settings['callback'] ) || empty( $settings['theme_handle'] ) ) {
+		return false;
+	}
+
+	// Current component is not supported
+	if ( ! in_array( $component, $settings['components'] ) ) {
+		return false;
+	}
+
+	// Finally return the settings
+	return $settings;
+}
+
+/**
+ * Get cover image Width and Height
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  string $component the BuddyPress component concerned ("xprofile" for user or "groups")
+ * @return array             an associative array containing the advised width and height for the cover image
+ */
+function bp_attachments_get_cover_image_dimensions( $component = 'xprofile' ) {
+	// Let's prevent notices when setting the warning strings
+	$default = array( 'width' => 0, 'height' => 0 );
+
+	$settings = bp_attachments_get_cover_image_settings( $component );
+
+	if ( empty( $settings ) ) {
+		return false;
+	}
+
+	// Get width and height
+	$wh = array_intersect_key( $settings, $default );
+
+	/**
+	 * Filter here to edit the cover image dimensions if needed.
+	 *
+	 * @since  BuddyPress (2.4.0)
+	 *
+	 * @param  array  $wh        an associative array containing the width and height values
+	 * @param  array  $settings  an associative array containing all the feature settings
+	 * @param  string $compnent  the requested component
+	 */
+	return apply_filters( 'bp_attachments_get_cover_image_dimensions', $wh, $settings, $component );
+}
+
+/**
+ * Are we on a page to edit a cover image ?
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @todo  The Groups single item part
+ * @return bool True if on a page to edit a cover image, false otherwise
+ */
+function bp_attachments_cover_image_is_edit() {
+	$retval = false;
+
+	$current_component = bp_current_component();
+	if ( 'profile' === $current_component ) {
+		$current_component = 'xprofile';
+	}
+
+	if ( ! bp_is_active( $current_component, 'cover_image' ) ) {
+		return $retval;
+	}
+
+	if ( bp_is_user_change_cover_image() ) {
+		$retval = ! bp_disable_avatar_uploads();
+	}
+
+	/**
+	 * @todo
+	 * if ( bp_is_group_change_cover_image() ) $retval = ! bp_disable_group_avatar_uploads();
+	 */
+
+	return apply_filters( 'bp_attachments_cover_image_is_edit', $retval, $current_component );
+}
+
+/**
+ * Get the url or the path for a type of attachment
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  string $data whether to get the url or the path
+ * @param  array  $args {
+ *     @type string $object_dir  The object dir (eg: members/groups). Defaults to members.
+ *     @type int    $item_id     The object id (eg: a user or a group id). Defaults to current user.
+ *     @type string $type        The type of the attachment which is also the subdir where files are saved.
+ *                               Defaults to 'cover-image'
+ *     @type string $file        The name of the file.
+ * }
+ * @return string|bool the url or the path to the attachment, false otherwise
+ */
+function bp_attachments_get_attachment( $data = 'url', $args = array() ) {
+	// Default value
+	$attachment_data = false;
+
+	$r = bp_parse_args( $args, array(
+		'object_dir' => 'members',
+		'item_id'    => bp_loggedin_user_id(),
+		'type'       => 'cover-image',
+		'file'       => '',
+	), 'attachments_get_attachment_src' );
+
+	// Get BuddyPress Upload Dir
+	$bp_upload_dir = bp_upload_dir();
+
+	$type_subdir = 'buddypress/' . $r['object_dir'] . '/' . $r['item_id'] . '/' . $r['type'];
+	$type_dir    = trailingslashit( $bp_upload_dir['basedir'] ) . $type_subdir;
+
+	if ( ! is_dir( $type_dir ) ) {
+		return $attachment_data;
+	}
+
+	if ( ! empty( $r['file'] ) ) {
+		if ( ! file_exists( trailingslashit( $type_dir ) . $r['file'] ) ) {
+			return $attachment_data;
+		}
+
+		if ( 'url' === $data ) {
+			$attachment_data = trailingslashit( $bp_upload_dir['baseurl'] ) . $type_subdir . '/' . $r['file'];
+		} else {
+			$attachment_data = trailingslashit( $type_dir ) . $r['file'];
+		}
+
+	} else {
+		$file = false;
+
+		// Open the directory and get the first file
+		if ( $att_dir = opendir( $type_dir ) ) {
+
+			while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
+				// Look for the first file having the type in its name
+				if ( false !== strpos( $attachment_file, $r['type'] ) && empty( $file ) ) {
+					$file = $attachment_file;
+					break;
+				}
+			}
+		}
+
+		if ( empty( $file ) ) {
+			return $attachment_data;
+		}
+
+		if ( 'url' === $data ) {
+			$attachment_data = trailingslashit( $bp_upload_dir['baseurl'] ) . $type_subdir . '/' . $file;
+		} else {
+			$attachment_data = trailingslashit( $type_dir ) . $file;
+		}
+	}
+
+	return $attachment_data;
+}
+
+/**
+ * Does the user has a cover image ?
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  int $user_id
+ * @return bool True if the user has a cover image, false otherwise
+ */
+function bp_attachments_get_user_has_cover_image( $user_id = 0 ) {
+	if ( empty( $user_id ) ) {
+		$user_id = bp_displayed_user_id();
+	}
+
+	$cover_src = bp_attachments_get_attachment( 'url', array(
+		'item_id'   => $user_id,
+	) );
+
+	return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $user_id );
+}
+
+/**
+ * Does the group has a cover image ?
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  int $group_id
+ * @return bool True if the group has a cover image, false otherwise
+ */
+function bp_attachments_get_group_has_cover_image( $group_id = 0 ) {
+	if ( empty( $group_id ) ) {
+		$group_id = bp_get_current_group_id();
+	}
+
+	$cover_src = bp_attachments_get_attachment( 'url', array(
+		'object_dir' => 'groups',
+		'item_id'    => $group_id,
+	) );
+
+	return (bool) apply_filters( 'bp_attachments_get_user_has_cover_image', $cover_src, $group_id );
+}
+
+/**
+ * Delete an attachment for the given arguments
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  array $args
+ * @see    bp_attachments_get_attachment() For more information on accepted arguments.
+ * @return bool True if the attachment was deleted, false otherwise
+ */
+function bp_attachments_delete_file( $args = array() ) {
+	$cover_path = bp_attachments_get_attachment( 'path', $args );
+
+	if ( empty( $cover_path ) ) {
+		return false;
+	}
+
+	@unlink( $cover_path );
+	return true;
+}
+
+/**
+ * Ajax Upload and set a cover image
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @return  string|null A json object containing success data if the upload succeeded
+ *                      error message otherwise.
+ */
+function bp_attachments_cover_image_ajax_upload() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+		wp_die();
+	}
+
+	/**
+	 * Sending the json response will be different if
+	 * the current Plupload runtime is html4
+	 */
+	$is_html4 = false;
+	if ( ! empty( $_POST['html4' ] ) ) {
+		$is_html4 = true;
+	}
+
+	// Check the nonce
+	check_admin_referer( 'bp-uploader' );
+
+	// Init the BuddyPress parameters
+	$bp_params = array();
+
+	// We need it to carry on
+	if ( ! empty( $_POST['bp_params' ] ) ) {
+		$bp_params = bp_parse_args( $_POST['bp_params' ], array(
+			'object'  => 'user',
+			'item_id' => bp_loggedin_user_id(),
+		), 'attachments_cover_image_ajax_upload' );
+	} else {
+		bp_attachments_json_response( false, $is_html4 );
+	}
+
+	// We need the object to set the uploads dir filter
+	if ( empty( $bp_params['object'] ) ) {
+		bp_attachments_json_response( false, $is_html4 );
+	}
+
+	// Capability check
+	if ( ! bp_attachments_current_user_can( 'edit_cover_image', $bp_params ) ) {
+		bp_attachments_json_response( false, $is_html4 );
+	}
+
+	$cover_image_attachment = new BP_Attachment_Cover_Image();
+	$uploaded = $cover_image_attachment->upload( $_FILES );
+
+	if ( ! empty( $uploaded['error'] ) ) {
+		// Upload error response
+		bp_attachments_json_response( false, $is_html4, array(
+			'type'    => 'upload_error',
+			'message' => sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $uploaded['error'] ),
+		) );
+	}
+
+	// Default object data
+	$object_data = array( 'dir' => 'members', 'component' => 'xprofile' );
+	if ( 'group' === $bp_params['object'] ) {
+		$object_data = array( 'dir' => 'groups', 'component' => 'groups' );
+	} elseif ( 'user' !== $bp_params['object'] ) {
+		$object_data = apply_filters( 'bp_attachments_cover_image_object_dir', $object_data, $bp_params['object'] );
+	}
+
+	// Get advised dimensions for the cover image
+	$dimensions = bp_attachments_get_cover_image_dimensions( $object_data['component'] );
+
+	// Resize the image so that it fit with the cover image dimensions
+	$cover_image  = $cover_image_attachment->fit( $uploaded['file'], $dimensions );
+	$is_too_small = false;
+
+	// Image is too small in width and height
+	if ( empty( $cover_image ) ) {
+		$cover_file = $cover_image_attachment->generate_filename( $uploaded['file'] );
+		@rename( $uploaded['file'], $cover_file );
+
+		// It's too small!
+		$is_too_small = true;
+	} elseif ( ! empty( $cover_image['path'] ) ) {
+		$cover_file   = $cover_image['path'];
+
+		if ( $cover_image['width'] < $dimensions['width'] || $cover_image['height'] < $dimensions['height'] ) {
+			$is_too_small = true;
+		}
+	}
+
+	// Default error message
+	$error_message = __( 'There was a problem uploading the cover image.', 'buddypress' );
+
+	if ( empty( $cover_file ) ) {
+		// Upload error response
+		bp_attachments_json_response( false, $is_html4, array(
+			'type'    => 'upload_error',
+			'message' => __( 'There was a problem uploading the cover image.', 'buddypress' ),
+		) );
+	}
+
+	// Set the basename for the cover file
+	$cover_basename = wp_basename( $cover_file );
+
+	// Get BuddyPress Upload Dir
+	$bp_upload_dir = bp_upload_dir();
+
+	$cover_subdir = 'buddypress/' . $object_data['dir'] . '/' . $bp_params['item_id'] . '/cover-image';
+	$cover_dir    = trailingslashit( $bp_upload_dir['basedir'] ) . $cover_subdir;
+
+	if ( ! is_dir( $cover_dir ) ) {
+		// Upload error response
+		bp_attachments_json_response( false, $is_html4, array(
+			'type'    => 'upload_error',
+			'message' => $error_message,
+		) );
+	}
+
+	// Clean up the cover dir to only keep the uploaded cover image
+	if ( $att_dir = opendir( $cover_dir ) ) {
+		while ( false !== ( $attachment_file = readdir( $att_dir ) ) ) {
+			// skip directories and the new cover image
+			if ( 2 < strlen( $attachment_file ) && 0 !== strpos( $attachment_file, '.' ) && $cover_basename !== $attachment_file ) {
+				@unlink( $cover_dir . '/' . $attachment_file );
+			}
+		}
+	}
+
+	// Build the url to the file
+	$cover_url = trailingslashit( $bp_upload_dir['baseurl'] ) . $cover_subdir . '/' . $cover_basename;
+
+	// Init Feedback code, 1 is success
+	$feedback_code = 1;
+
+	// 0 is the size warning
+	if ( $is_too_small ) {
+		$feedback_code = 0;
+	}
+
+	// Set the name of the file
+	$name = $_FILES['file']['name'];
+	$name_parts = pathinfo( $name );
+	$name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) );
+
+	// Build the successful response
+	$response = array(
+		'name'          => $name,
+		'url'           => $cover_url,
+		'feedback_code' => $feedback_code,
+	);
+
+	// User already has a cover image
+	if ( "true" === $bp_params['has_cover_image'] ) {
+		$response['had_cover_image'] = true;
+
+	// Get the style in case it's not already loaded
+	} else {
+		$response['header']       = bp_buffer_template_part( 'members/single/cover-image-header', null, false );
+		$response['inline_style'] = bp_add_cover_image_inline_css( true );
+	}
+
+	// Finally return the cover image to the UI
+	bp_attachments_json_response( true, $is_html4, $response );
+}
+add_action( 'wp_ajax_bp_cover_image_upload', 'bp_attachments_cover_image_ajax_upload' );
+
+/**
+ * Ajax delete a cover image for a given object and item id.
+ *
+ * @since BuddyPress (2.4.0)
+ *
+ * @return string|null A json object containing success data if the cover image was deleted
+ *                     error message otherwise.
+ */
+function bp_attachments_cover_image_ajax_delete() {
+	// Bail if not a POST action.
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+		wp_send_json_error();
+	}
+
+	$cover_image_data = $_POST;
+
+	if ( empty( $cover_image_data['object'] ) || empty( $cover_image_data['item_id'] ) ) {
+		wp_send_json_error();
+	}
+
+	// Check the nonce
+	check_admin_referer( 'bp_delete_cover_image', 'nonce' );
+
+	// Capability check
+	if ( ! bp_attachments_current_user_can( 'edit_cover_image', $cover_image_data ) ) {
+		wp_send_json_error();
+	}
+
+	// Set object for the user's case
+	if ( 'user' === $cover_image_data['object'] ) {
+		$object = 'member';
+
+	// Set it for any other cases
+	} else {
+		$object = $cover_image_data['object'];
+	}
+
+	// Set the object dir
+	$dir = $object . 's';
+
+	// Handle delete
+	if ( bp_attachments_delete_file( array( 'item_id' => $cover_image_data['item_id'], 'object_dir' => $dir, 'type' => 'cover-image' ) ) ) {
+
+		wp_send_json_success( array(
+			'header'        => bp_buffer_template_part( $dir . '/single/' . $object . '-header', null, false ),
+			'feedback_code' => 3,
+		) );
+	} else {
+		wp_send_json_error( array(
+			'feedback_code' => 2,
+		) );
+	}
+}
+add_action( 'wp_ajax_bp_cover_image_delete', 'bp_attachments_cover_image_ajax_delete' );
diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php
index 7d1e0be..0da6fbb 100644
--- src/bp-core/bp-core-classes.php
+++ src/bp-core/bp-core-classes.php
@@ -23,3 +23,4 @@ require dirname( __FILE__ ) . '/classes/class-bp-recursive-query.php';
 require dirname( __FILE__ ) . '/classes/class-bp-media-extractor.php';
 require dirname( __FILE__ ) . '/classes/class-bp-attachment.php';
 require dirname( __FILE__ ) . '/classes/class-bp-attachment-avatar.php';
+require dirname( __FILE__ ) . '/classes/class-bp-attachment-cover-image.php';
diff --git src/bp-core/bp-core-cssjs.php src/bp-core/bp-core-cssjs.php
index 392f926..7933f43 100644
--- src/bp-core/bp-core-cssjs.php
+++ src/bp-core/bp-core-cssjs.php
@@ -43,6 +43,9 @@ function bp_core_register_common_scripts() {
 		'bp-avatar'   => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'jcrop' ), 'footer' => true ),
 		'bp-webcam'   => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ),
 
+		// 2.4
+		'bp-cover-image' => array( 'file' => "{$url}cover-image{$min}.js", 'dependencies' => array(), 'footer' => true ),
+
 	) );
 
 	$version = bp_get_version();
@@ -140,6 +143,21 @@ function bp_core_avatar_scripts() {
 add_action( 'bp_enqueue_scripts', 'bp_core_avatar_scripts' );
 
 /**
+ * Enqueues the css and js required by the Cover Image UI.
+ *
+ * @since  BuddyPress (2.4.0)
+ */
+function bp_core_cover_image_scripts() {
+	if ( ! bp_attachments_cover_image_is_edit() ) {
+		return false;
+	}
+
+	// Enqueue the Attachments scripts for the Cover Image UI
+	bp_attachments_enqueue_scripts( 'BP_Attachment_Cover_Image' );
+}
+add_action( 'bp_enqueue_scripts', 'bp_core_cover_image_scripts' );
+
+/**
  * Enqueues jCrop library and hooks BP's custom cropper JS.
  */
 function bp_core_add_jquery_cropper() {
@@ -337,3 +355,105 @@ function bp_core_get_js_dependencies() {
 		'bp-jquery-scroll-to'
 	) );
 }
+
+/**
+ * Add inline css to display the component's single item cover image
+ *
+ * @since BuddyPress (2.4.0)
+ *
+ * @param  bool $return true to get the inline css
+ * @return string|array the inline css or an associative array containing
+ *                      the css rules and the style handle
+ */
+function bp_add_cover_image_inline_css( $return = false ) {
+	$bp = buddypress();
+
+	// Find the component of the current item
+	if ( bp_is_user() ) {
+
+		// No user uploads, no need to carry on
+		if ( bp_disable_avatar_uploads() ) {
+			return;
+		}
+
+		$cover_image_object = array(
+			'component' => 'xprofile',
+			'object' => $bp->displayed_user
+		);
+	} elseif ( bp_is_group() ) {
+
+		// No user uploads, no need to carry on
+		if ( bp_disable_group_avatar_uploads() ) {
+			return;
+		}
+
+		$cover_image_object = array(
+			'component' =>'groups',
+			'object' => $bp->groups->current_group
+		);
+	} else {
+		$cover_image_object = apply_filters( 'bp_current_cover_image_object_inline_css', array() );
+	}
+
+	// Bail if no component were found.
+	if ( empty( $cover_image_object['component'] ) || empty( $cover_image_object['object'] ) || ! bp_is_active( $cover_image_object['component'], 'cover_image' ) ) {
+		return;
+	}
+
+	// Get the settings of the cover image feature for the current component
+	$params = bp_attachments_get_cover_image_settings( $cover_image_object['component'] );
+
+	// Bail if no params.
+	if ( empty( $params ) ) {
+		return;
+	}
+
+	// Try to call the callback
+	if ( is_callable( $params['callback'] ) ) {
+
+		$object_dir = $cover_image_object['component'];
+
+		if ( 'xprofile' === $object_dir ) {
+			$object_dir = 'members';
+		}
+
+		$cover_image = bp_attachments_get_attachment( 'url', array(
+			'object_dir' => $object_dir,
+			'item_id'    => $cover_image_object['object']->id,
+		) );
+
+		if ( empty( $cover_image ) ) {
+			if ( ! empty( $params['default_cover'] ) ) {
+				$cover_image = $params['default_cover'];
+			}
+		}
+
+		// Object has a cover so update it!
+		$cover_image_object['object']->has_cover_image = true;
+
+		$inline_css = call_user_func_array( $params['callback'], array( array(
+			'cover_image' => esc_url( $cover_image ),
+			'component'   => sanitize_key( $cover_image_object['component'] ),
+			'object_id'   => (int) $cover_image_object['object']->id,
+			'width'       => (int) $params['width'],
+			'height'      => (int) $params['height'],
+		) ) );
+
+		// Finally add the inline css to the handle
+		if ( ! empty( $inline_css ) ) {
+
+			// Used to get the css when Ajax setting the cover image
+			if ( true === $return ) {
+				return array(
+					'css_rules' => '<style type="text/css">' . "\n" . $inline_css . "\n" . '</style>',
+					'handle'    => $params['theme_handle'],
+				);
+			}
+
+			wp_add_inline_style( $params['theme_handle'], $inline_css );
+		} else {
+			return false;
+		}
+	}
+}
+add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 );
diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
index 52bae24..ef740f5 100644
--- src/bp-core/bp-core-template.php
+++ src/bp-core/bp-core-template.php
@@ -1934,6 +1934,11 @@ function bp_is_active( $component = '', $feature = '' ) {
 
 		// Is feature active?
 		if ( ! empty( $feature ) ) {
+			// The xProfile component is specific
+			if ( 'xprofile' === $component ) {
+				$component = 'profile';
+			}
+
 			if ( empty( buddypress()->$component->features ) || false === in_array( $feature, buddypress()->$component->features, true ) ) {
 				$retval = false;
 			}
@@ -2247,6 +2252,19 @@ function bp_is_user_change_avatar() {
 }
 
 /**
+ * Is the current page the a user's change cover image profile page?
+ *
+ * Eg http://example.com/members/joe/profile/change-cover-image/ (or a subpage thereof).
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @return True if the current page is a user's profile edit cover image page.
+ */
+function bp_is_user_change_cover_image() {
+	return (bool) ( bp_is_profile_component() && bp_is_current_action( 'change-cover-image' ) );
+}
+
+/**
  * Is this a user's forums page?
  *
  * Eg http://example.com/members/joe/forums/ (or a subpage thereof).
diff --git src/bp-core/bp-core-theme-compatibility.php src/bp-core/bp-core-theme-compatibility.php
index 897b775..9240936 100644
--- src/bp-core/bp-core-theme-compatibility.php
+++ src/bp-core/bp-core-theme-compatibility.php
@@ -437,6 +437,88 @@ function bp_set_theme_compat_original_template( $template = '' ) {
 }
 
 /**
+ * Set a theme compat feature
+ *
+ * @since BuddyPress (2.4.0)
+ *
+ * @param  string $theme_id the theme id (eg: legacy)
+ * @param  array  $feature  an associative array (eg: array( name => 'feature_name', 'settings' => array() ))
+ */
+function bp_set_theme_compat_feature( $theme_id, $feature = array() ) {
+	if ( empty( $theme_id ) || empty( $feature['name'] ) ) {
+		return;
+	}
+
+	// Get BuddyPress instance
+	$bp = buddypress();
+
+	// Get current theme compat theme
+	$theme_compat_theme = $bp->theme_compat->theme;
+
+	// Bail if theme is not in use
+	if ( $theme_id !== $theme_compat_theme->id ) {
+		return;
+	}
+
+	$features = $theme_compat_theme->__get( 'features' );
+	if ( empty( $features ) ) {
+		$features = array();
+	}
+
+	// Bail if the feature is already registered or no settings were provided
+	if ( isset( $features[ $feature['name'] ] ) || empty( $feature['settings'] ) ) {
+		return;
+	}
+
+	// Add the feature
+	$features[ $feature['name'] ] = (object) $feature['settings'];
+
+	// The feature is attached to components
+	if ( isset( $features[ $feature['name'] ]->components ) ) {
+		// Set the feature for each concerned component
+		foreach ( (array) $features[ $feature['name'] ]->components as $component ) {
+			// The xProfile component is specific
+			if ( 'xprofile' === $component ) {
+				$component = 'profile';
+			}
+
+			if ( isset( $bp->{$component} ) ) {
+				if ( isset( $bp->{$component}->features ) ) {
+					$bp->{$component}->features[] = $feature['name'];
+				} else {
+					$bp->{$component}->features = array( $feature['name'] );
+				}
+			}
+		}
+	}
+
+	// Finally update the theme compat features
+	$theme_compat_theme->__set( 'features', $features );
+}
+
+/**
+ * Get a theme compat feature
+ *
+ * @since BuddyPress (2.4.0)
+ *
+ * @param  string $feature the feature (eg: cover_image)
+ * @return object          the feature settings.
+ */
+function bp_get_theme_compat_feature( $feature = '' ) {
+	// Get current theme compat theme
+	$theme_compat_theme = buddypress()->theme_compat->theme;
+
+	// Get features
+	$features = $theme_compat_theme->__get( 'features' );
+
+	if ( ! isset( $features[ $feature ] ) ) {
+		return false;
+	}
+
+	return $features[ $feature ];
+}
+
+/**
  * Check whether a given template is the one that WP originally selected to display current page.
  *
  * @since BuddyPress (1.7.0)
diff --git src/bp-core/classes/class-bp-attachment-cover-image.php src/bp-core/classes/class-bp-attachment-cover-image.php
new file mode 100644
index 0000000..0b8a741
--- /dev/null
+++ src/bp-core/classes/class-bp-attachment-cover-image.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * Core Cover Image attachment class.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * BP Attachment Cover Image class.
+ *
+ * Extends BP Attachment to manage the cover images uploads.
+ *
+ * @since BuddyPress (2.4.0)
+ */
+class BP_Attachment_Cover_Image extends BP_Attachment {
+	/**
+	 * The constuctor
+	 *
+	 * @since BuddyPress (2.4.0)
+	 */
+	public function __construct() {
+		parent::__construct( array(
+			'action'             => 'bp_cover_image_upload',
+			'file_input'         => 'file',
+			'base_dir'           => 'buddypress',
+			'required_wp_files'  => array( 'file', 'image' ),
+
+			/* @todo use a custom error, like we are doing for avatars */
+			'allowed_mime_types' => array( 'jpg', 'png', 'gif' ),
+		) );
+	}
+
+	/**
+	 * Set the directory when uploading a file
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @return array upload data (path, url, basedir...)
+	 */
+	public function upload_dir_filter() {
+		// Default values are for profiles
+		$object_id = bp_displayed_user_id();
+
+		if ( empty( $object_id ) ) {
+			$object_id = bp_loggedin_user_id();
+		}
+
+		$object_directory = 'members';
+
+		// We're in a group, edit default values
+		if ( bp_is_group() ) {
+			$object_id        = bp_get_current_group_id();
+			$object_directory = 'groups';
+		}
+
+		// Set the subdir
+		$subdir  = '/' . $object_directory . '/' . $object_id . '/cover-image';
+
+		return apply_filters( 'bp_attachments_cover_image_upload_datas', array(
+			'path'    => $this->upload_path . $subdir,
+			'url'     => $this->url . $subdir,
+			'subdir'  => $subdir,
+			'basedir' => $this->upload_path,
+			'baseurl' => $this->url,
+			'error'   => false
+		) );
+	}
+
+	/**
+	 * Adjust the cover image to fit with advised width & height.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param string $file the absolute path to the file.
+	 * @return mixed
+	 */
+	public function fit( $file = '', $dimensions = array() ) {
+		if ( empty( $dimensions['width'] ) || empty( $dimensions['height'] ) ) {
+			return false;
+		}
+
+		// Get image size
+		$size   = @getimagesize( $file );
+		$retval = false;
+
+		// Check image size and shrink if too large
+		if ( $size[0] > $dimensions['width'] || $size[1] > $dimensions['height'] ) {
+			$editor = wp_get_image_editor( $file );
+
+			if ( ! is_wp_error( $editor ) ) {
+				$editor->set_quality( 100 );
+
+				$resized = $editor->resize( $dimensions['width'], $dimensions['height'], true );
+				if ( ! is_wp_error( $resized ) ) {
+					$cover   = $editor->save( $this->generate_filename( $file ) );
+				} else {
+					$retval = $resized;
+				}
+
+				// Check for cover creation errors
+				if ( ( false === $retval ) && is_wp_error( $cover ) ) {
+					$retval = $cover;
+				}
+
+				// Cover is good so proceed
+				if ( false === $retval ) {
+					$retval = $cover;
+				}
+
+			} else {
+				$retval = $editor;
+			}
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Generate a filename for the cover image
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param  string $file the absolute path to the file.
+	 * @return string       the absolute path to the new file name
+	 */
+	public function generate_filename( $file = '' ) {
+		if ( empty( $file ) || ! file_exists( $file ) ) {
+			return false;
+		}
+
+		$info    = pathinfo( $file );
+		$dir     = $info['dirname'];
+		$ext     = strtolower( $info['extension'] );
+		$name    = wp_hash( $file . time() ) . '-bp-cover-image';
+
+		return trailingslashit( $dir ) . "{$name}.{$ext}";
+	}
+
+	/**
+	 * Build script datas for the Uploader UI
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @return array the javascript localization data
+	 */
+	public function script_data() {
+		// Get default script data
+		$script_data = parent::script_data();
+
+		if ( bp_is_user() ) {
+			$item_id = bp_displayed_user_id();
+
+			$script_data['bp_params'] = array(
+				'object'          => 'user',
+				'item_id'         => $item_id,
+				'has_cover_image' => bp_attachments_get_user_has_cover_image( $item_id ),
+				'nonces'  => array(
+					'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
+				),
+			);
+
+			// Set feedback messages
+			$script_data['feedback_messages'] = array(
+				1 => __( 'Your new cover image was uploaded successfully.', 'buddypress' ),
+				2 => __( 'There was a problem deleting your cover image. Please try again.', 'buddypress' ),
+				3 => __( 'Your cover image was deleted successfully!', 'buddypress' ),
+			);
+		} elseif ( bp_is_group() ) {
+			$item_id = bp_get_current_group_id();
+
+			$script_data['bp_params'] = array(
+				'object'          => 'group',
+				'item_id'         => bp_get_current_group_id(),
+				'has_cover_image' => bp_attachments_get_group_has_cover_image( $item_id ),
+				'nonces'  => array(
+					'remove' => wp_create_nonce( 'bp_delete_cover_image' ),
+				),
+			);
+
+			// Set feedback messages
+			$script_data['feedback_messages'] = array(
+				1 => __( 'The group cover image was uploaded successfully.', 'buddypress' ),
+				2 => __( 'There was a problem deleting the group cover image. Please try again.', 'buddypress' ),
+				3 => __( 'The group cover image was deleted successfully!', 'buddypress' ),
+			);
+		} else {
+			/**
+			 * Use this filter to include specific BuddyPress params for your object.
+			 * e.g. Cover image for blogs single item.
+			 *
+			 * @since BuddyPress (2.4.0)
+			 *
+			 * @param array $value The cover image specific BuddyPress parameters.
+			 */
+			$script_data['bp_params'] = apply_filters( 'bp_attachment_cover_image_params', array() );
+		}
+
+		// Include our specific js & css
+		$script_data['extra_js']  = array( 'bp-cover-image' );
+		$script_data['extra_css'] = array( 'bp-avatar' );
+
+		return apply_filters( 'bp_attachments_cover_image_script_data', $script_data );
+	}
+}
diff --git src/bp-core/css/avatar.css src/bp-core/css/avatar.css
index 385852f..2986dff 100644
--- src/bp-core/css/avatar.css
+++ src/bp-core/css/avatar.css
@@ -1,26 +1,31 @@
-div.bp-avatar-status {
+div.bp-avatar-status,
+div.bp-cover-image-status {
 	clear: both;
 	margin: 1em 0;
 }
 
-div.bp-avatar-status p.updated {
+div.bp-avatar-status p.updated,
+div.bp-cover-image-status p.updated {
 	display: block;
 	padding: 10px 15px;
 }
 
-div.bp-avatar-status p.success {
+div.bp-avatar-status p.success,
+div.bp-cover-image-status p.success {
 	background-color: #efc;
 	border: 1px solid #591;
 	color: #250;
 }
 
-div.bp-avatar-status p.error {
+div.bp-avatar-status p.error,
+div.bp-cover-image-status p.error {
 	background-color: #fdc;
 	border: 1px solid #a00;
 	color: #800;
 }
 
-div.bp-avatar-status .bp-progress {
+div.bp-avatar-status .bp-progress,
+div.bp-cover-image-status .bp-progress {
 	background: none;
 	border: 1px solid #d1d1d1;
 	float: right;
@@ -33,7 +38,8 @@ div.bp-avatar-status .bp-progress {
 	width: 200px;
 }
 
-div.bp-avatar-status .bp-bar {
+div.bp-avatar-status .bp-bar,
+div.bp-cover-image-status .bp-bar {
 	background-color: #c3ff88;
 	width: 0;
 	height: 100%;
diff --git src/bp-core/js/cover-image.js src/bp-core/js/cover-image.js
new file mode 100644
index 0000000..b8c466b
--- /dev/null
+++ src/bp-core/js/cover-image.js
@@ -0,0 +1,263 @@
+/* global bp, BP_Uploader, _, Backbone */
+
+window.bp = window.bp || {};
+
+( function( exports, $ ) {
+
+	// Bail if not set
+	if ( typeof BP_Uploader === 'undefined' ) {
+		return;
+	}
+
+	bp.Models      = bp.Models || {};
+	bp.Collections = bp.Collections || {};
+	bp.Views       = bp.Views || {};
+
+	bp.CoverImage = {
+		start: function() {
+
+			// Init some vars
+			this.views    = new Backbone.Collection();
+			this.warning = null;
+
+			// Set up views
+			this.uploaderView();
+
+			// Inform about the needed dimensions
+			this.displayWarning( BP_Uploader.strings.cover_image_warnings.dimensions );
+
+			// Set up the delete view if needed
+			if ( true === BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image ) {
+				this.deleteView();
+			}
+		},
+
+		uploaderView: function() {
+			// Listen to the Queued uploads
+			bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this );
+
+			// Create the BuddyPress Uploader
+			var uploader = new bp.Views.Uploader();
+
+			// Add it to views
+			this.views.add( { id: 'upload', view: uploader } );
+
+			// Display it
+			uploader.inject( '.bp-cover-image' );
+		},
+
+		uploadProgress: function() {
+			// Create the Uploader status view
+			var coverImageUploadProgress = new bp.Views.coverImageUploadProgress( { collection: bp.Uploader.filesQueue } );
+
+			if ( ! _.isUndefined( this.views.get( 'status' ) ) ) {
+				this.views.set( { id: 'status', view: coverImageUploadProgress } );
+			} else {
+				this.views.add( { id: 'status', view: coverImageUploadProgress } );
+			}
+
+			// Display it
+	 		coverImageUploadProgress.inject( '.bp-cover-image-status' );
+		},
+
+		deleteView: function() {
+			// Create the delete model
+			var delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params,
+				'object',
+				'item_id',
+				'nonces'
+			) );
+
+			// Do not add it if already there!
+			if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
+				return;
+			}
+
+			// Create the delete view
+			var deleteView = new bp.Views.DeleteCoverImage( { model: delete_model } );
+
+			// Add it to views
+			this.views.add( { id: 'delete', view: deleteView } );
+
+			// Display it
+			deleteView.inject( '.bp-cover-image-manage' );
+		},
+
+		deleteCoverImage: function( model ) {
+			var self = this,
+				deleteView;
+
+			// Remove the delete view
+			if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) {
+				deleteView = this.views.get( 'delete' );
+				deleteView.get( 'view' ).remove();
+				this.views.remove( { id: 'delete', view: deleteView } );
+			}
+
+			// Remove the cover image !
+			bp.ajax.post( 'bp_cover_image_delete', {
+				json:          true,
+				item_id:       model.get( 'item_id' ),
+				object:        model.get( 'object' ),
+				nonce:         model.get( 'nonces' ).remove
+			} ).done( function( response ) {
+				var coverImageStatus = new bp.Views.CoverImageStatus( {
+					value : BP_Uploader.strings.feedback_messages[ response.feedback_code ],
+					type : 'success'
+				} );
+
+				self.views.add( {
+					id   : 'status',
+					view : coverImageStatus
+				} );
+
+				coverImageStatus.inject( '.bp-cover-image-status' );
+
+				// Reset the item header
+				$( '#item-header' ).html( response.header );
+
+				// Reset the has_cover_image bp_param
+				BP_Uploader.settings.defaults.multipart_params.bp_params.has_cover_image = false;
+
+			} ).fail( function( response ) {
+				var feedback = BP_Uploader.strings.default_error;
+				if ( ! _.isUndefined( response ) ) {
+					feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ];
+				}
+
+				var coverImageStatus = new bp.Views.CoverImageStatus( {
+					value : feedback,
+					type : 'error'
+				} );
+
+				self.views.add( {
+					id   : 'status',
+					view : coverImageStatus
+				} );
+
+				coverImageStatus.inject( '.bp-cover-image-status' );
+
+				// Put back the delete view
+				bp.CoverImage.deleteView();
+			} );
+		},
+
+		removeWarning: function() {
+			if ( ! _.isNull( this.warning ) ) {
+				this.warning.remove();
+			}
+		},
+
+		displayWarning: function( message ) {
+			this.removeWarning();
+
+			this.warning = new bp.Views.uploaderWarning( {
+				value: message
+			} );
+
+			this.warning.inject( '.bp-cover-image-status' );
+		},
+
+		// Dynamically set the cover without a page reload
+		setCover: function( cover ) {
+			if ( ! _.isUndefined( cover.had_cover_image ) ) {
+				$( '#header-cover-image' ).css( {
+					'background-image': 'url( ' + cover.url + ' )'
+				} );
+			} else if ( ! _.isUndefined( cover.header ) ) {
+				if ( ! $( '#header-cover-image' ).length ) {
+					$( '#item-header' ).html( cover.header );
+
+					// Check we have everything we need
+					if ( ! _.isUndefined( cover.inline_style.handle ) && ! _.isUndefined( cover.inline_style.css_rules ) ) {
+						if ( ! $( '#' + cover.inline_style.handle + '-inline-css').length ) {
+							$( '#item-header' ).prepend( cover.inline_style.css_rules );
+						}
+					}
+
+				} else {
+					$( '#header-cover-image' ).css( {
+						'background-image': 'url( ' + cover.url + ' )'
+					} );
+				}
+			}
+		}
+	};
+
+	// Custom Uploader Files view
+	bp.Views.coverImageUploadProgress = bp.Views.uploaderStatus.extend( {
+		className: 'files',
+
+		initialize: function() {
+			bp.Views.uploaderStatus.prototype.initialize.apply( this, arguments );
+
+			this.collection.on( 'change:url', this.uploadResult, this );
+		},
+
+		uploadResult: function( model ) {
+			var message, type;
+
+			if ( ! _.isUndefined( model.get( 'url' ) ) ) {
+
+				// Image is too small
+				if ( 0 === model.get( 'feedback_code' ) ) {
+					message = BP_Uploader.strings.cover_image_warnings.dimensions;
+					type    = 'warning';
+
+				// Success, Rock n roll!
+				} else {
+					message = BP_Uploader.strings.feedback_messages[ model.get( 'feedback_code' ) ];
+					type = 'success';
+				}
+
+				this.views.set( '.bp-uploader-progress', new bp.Views.CoverImageStatus( {
+					value : message,
+					type  : type
+				} ) );
+
+				// Update the header
+				bp.CoverImage.setCover( _.pick( model.attributes, 'url', 'had_cover_image', 'inline_style', 'header' ) );
+
+				// Add the delete view
+				bp.CoverImage.deleteView();
+			}
+		}
+	} );
+
+	// BuddyPress Cover Image Feedback view
+	bp.Views.CoverImageStatus = bp.View.extend( {
+		tagName: 'p',
+		className: 'updated',
+		id: 'bp-cover-image-feedback',
+
+		initialize: function() {
+			this.el.className += ' ' + this.options.type;
+			this.value = this.options.value;
+		},
+
+		render: function() {
+			this.$el.html( this.value );
+			return this;
+		}
+	} );
+
+	// BuddyPress Cover Image Delete view
+	bp.Views.DeleteCoverImage = bp.View.extend( {
+		tagName: 'div',
+		id: 'bp-delete-cover-image-container',
+		template: bp.template( 'bp-cover-image-delete' ),
+
+		events: {
+			'click #bp-delete-cover-image': 'deleteCoverImage'
+		},
+
+		deleteCoverImage: function( event ) {
+			event.preventDefault();
+
+			bp.CoverImage.deleteCoverImage( this.model );
+		}
+	} );
+
+	bp.CoverImage.start();
+
+})( bp, jQuery );
diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
index f4d482f..ee11912 100644
--- src/bp-members/bp-members-template.php
+++ src/bp-members/bp-members-template.php
@@ -1467,6 +1467,29 @@ function bp_get_displayed_user_nav() {
 	}
 }
 
+/** Cover image ***************************************************************/
+
+/**
+ * Does the displayed user has a cover image
+ *
+ * @since BuddyPress (2.4.0)
+ *
+ * @return bool True if the displayed user has a cover image,
+ *              False otherwise
+ */
+function bp_displayed_user_has_cover_image() {
+	$bp = buddypress();
+
+	/**
+	 * Filters the displayed user's check about his cover image.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param bool $value whether the user has a cover image or not.
+	 */
+	return (bool) apply_filters( 'bp_displayed_user_has_cover_image', ! empty( $bp->displayed_user->has_cover_image ) );
+}
+
 /** Avatars *******************************************************************/
 
 /**
diff --git src/bp-templates/bp-legacy/buddypress-functions.php src/bp-templates/bp-legacy/buddypress-functions.php
index fb7cdb4..d9fc574 100644
--- src/bp-templates/bp-legacy/buddypress-functions.php
+++ src/bp-templates/bp-legacy/buddypress-functions.php
@@ -58,12 +58,81 @@ class BP_Legacy extends BP_Theme_Compat {
 	 * @access private
 	 */
 	protected function setup_globals() {
-		$bp            = buddypress();
-		$this->id      = 'legacy';
-		$this->name    = __( 'BuddyPress Legacy', 'buddypress' );
-		$this->version = bp_get_version();
-		$this->dir     = trailingslashit( $bp->themes_dir . '/bp-legacy' );
-		$this->url     = trailingslashit( $bp->themes_url . '/bp-legacy' );
+		$bp             = buddypress();
+		$this->id       = 'legacy';
+		$this->name     = __( 'BuddyPress Legacy', 'buddypress' );
+		$this->version  = bp_get_version();
+		$this->dir      = trailingslashit( $bp->themes_dir . '/bp-legacy' );
+		$this->url      = trailingslashit( $bp->themes_url . '/bp-legacy' );
+
+		// Set Up theme features
+		$this->setup_features();
+	}
+
+	/**
+	 * Setup the theme's features
+	 *
+	 * @since BuddyPress (2.4.0)
+	 * @access public
+	 *
+	 * @global $content_width the content width of the theme
+	 */
+	public function setup_features() {
+		global $content_width;
+
+		// Get the theme
+		$current_theme = wp_get_theme();
+		$theme_handle  = $current_theme->get_stylesheet();
+		$parent        = $current_theme->parent();
+
+		if ( $parent ) {
+			$theme_handle = $parent->get_stylesheet();
+		}
+
+		/**
+		 * Since Companion stylesheets, the $content_width is smaller
+		 * than the width used by BuddyPress, so we need to manually set the
+		 * content width for the concerned themes.
+		 *
+		 * array( stylesheet => content width used by BuddyPress )
+		 */
+		$bp_content_widths = array(
+			'twentyfifteen'  => 1300,
+			'twentyfourteen' => 955,
+			'twentythirteen' => 890,
+		);
+
+		// Default values
+		$bp_content_width = (int) $content_width;
+		$bp_handle        = 'bp-legacy-css';
+
+		// Specific to themes having companion stylesheets
+		if ( isset( $bp_content_widths[ $theme_handle ] ) ) {
+			$bp_content_width = $bp_content_widths[ $theme_handle ];
+			$bp_handle        = 'bp-' . $theme_handle;
+		}
+
+		if ( is_rtl() ) {
+			$bp_handle .= '-rtl';
+		}
+
+		$top_offset    = 150;
+		$avatar_height = apply_filters( 'bp_core_avatar_full_height', $top_offset );
+
+		if ( $avatar_height > $top_offset ) {
+			$top_offset = $avatar_height;
+		}
+
+		bp_set_theme_compat_feature( $this->id, array(
+			'name'     => 'cover_image',
+			'settings' => array(
+				'components'   => array( 'xprofile', 'groups' ),
+				'width'        => $bp_content_width,
+				'height'       => $top_offset + round( $avatar_height / 2 ),
+				'callback'     => 'bp_legacy_theme_cover_image',
+				'theme_handle' => $bp_handle,
+			),
+		) );
 	}
 
 	/**
@@ -1717,3 +1786,123 @@ function bp_legacy_theme_ajax_messages_star_handler() {
 	echo '-1';
 	die();
 }
+
+/**
+ * BP Legacy's callback for the cover image feature
+ *
+ * @since  BuddyPress (2.4.0)
+ *
+ * @param  array  $params the current component's feature parameters
+ * @return array          an array to inform about the css handle to attach the css rules to
+ */
+function bp_legacy_theme_cover_image( $params = array() ) {
+	if ( empty( $params ) ) {
+		return;
+	}
+
+	// avatar height - padding - 1/2 avatar height
+	$avatar_offset = $params['height'] - 5 - round( (int) bp_core_avatar_full_height() / 2 );
+
+	// header content offset + spacing
+	$top_offset  = bp_core_avatar_full_height() - 10;
+	$left_offset = bp_core_avatar_full_width() + 20;
+
+	$cover_image = isset( $params['cover_image'] ) ? 'background-image: url(' . $params['cover_image'] . ');' : '';
+
+	/**
+	 * @todo groups single item rules, most of the css should be in companion stylesheets..
+	 */
+	return '
+		/* Cover image */
+		#buddypress #header-cover-image {
+			height: ' . $params["height"] . 'px;
+			' . $cover_image . '
+		}
+
+		.bp-user #buddypress #item-header {
+			padding-top: 0;
+		}
+
+		#buddypress #item-header-cover-image #item-header-avatar {
+			margin-top: '. $avatar_offset .'px;
+			float: none;
+			overflow:visible;
+			width:auto;
+		}
+
+		#buddypress div#item-header #item-header-cover-image #item-header-content {
+			clear: both;
+			float: left;
+			margin-left: ' . $left_offset . 'px;
+			margin-top: -' . $top_offset . 'px;
+			width:auto;
+		}
+
+		/* This should only happen on regular screens */
+		#buddypress div#item-header-cover-image h2 a,
+		#buddypress div#item-header-cover-image h2 {
+			color: #FFF;
+			text-rendering: optimizelegibility;
+			text-shadow: 0px 0px 3px rgba( 0, 0, 0, 0.8 );
+			margin: 0;
+			font-size:200%;
+		}
+
+		#buddypress #item-header-cover-image #item-header-avatar img.avatar {
+			border: solid 2px #FFF;
+			background: rgba( 255, 255, 255, 0.8 );
+		}
+
+		#buddypress #item-header-cover-image #item-buttons {
+			overflow:hidden;
+			margin: 20px 0 10px;
+			padding: 0 0 5px;
+		}
+
+		#buddypress #item-header-cover-image #item-buttons:before {
+			content:"\00a0";
+		}
+
+		@media screen and (max-width: 782px) {
+			#buddypress #item-header-cover-image #item-header-avatar,
+			.bp-user #buddypress #item-header #item-header-cover-image #item-header-avatar,
+			#buddypress div#item-header #item-header-cover-image #item-header-content {
+				width:100%;
+				text-align:center;
+			}
+
+			#buddypress #item-header-cover-image #item-header-avatar a {
+				display:inline-block;
+			}
+
+			#buddypress #item-header-cover-image #item-header-avatar img {
+				margin:0;
+			}
+
+			#buddypress div#item-header #item-header-cover-image #item-header-content {
+				margin:0;
+			}
+
+			#buddypress div#item-header-cover-image h2 a,
+			#buddypress div#item-header-cover-image h2 {
+				color: inherit;
+				text-shadow: none;
+				margin:25px 0 0;
+				font-size:200%;
+			}
+
+			#buddypress #item-header-cover-image #item-buttons div {
+				float:none;
+				display:inline-block;
+			}
+
+			#buddypress #item-header-cover-image #item-buttons:before {
+				content:"";
+			}
+
+			#buddypress #item-header-cover-image #item-buttons {
+				margin: 5px 0;
+			}
+		}
+	';
+}
diff --git src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php
new file mode 100644
index 0000000..a552682
--- /dev/null
+++ src/bp-templates/bp-legacy/buddypress/assets/_attachments/cover-images/index.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * BuddyPress Cover Images main template
+ *
+ * This template is used to inject the BuddyPress Backbone views
+ * dealing with cover images.
+ * It's also used to create the common Backbone views
+ *
+ * @since 2.4
+ *
+ * @package BuddyPress
+ * @subpackage bp-attachments
+ */
+?>
+
+<div class="bp-cover-image"></div>
+<div class="bp-cover-image-status"></div>
+<div class="bp-cover-image-manage"></div>
+
+<?php bp_attachments_get_template_part( 'uploader' ); ?>
+
+<script id="tmpl-bp-cover-image-delete" type="text/html">
+	<# if ( 'user' === data.object ) { #>
+		<p><?php _e( "If you'd like to delete your current cover image but not upload a new one, please use the delete Cover Image button.", 'buddypress' ); ?></p>
+		<p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete My Cover Image', 'buddypress' ); ?></a></p>
+	<# } else if ( 'group' === data.object ) { #>
+		<p><?php _e( "If you'd like to remove the existing group cover image but not upload a new one, please use the delete group cover image button.", 'buddypress' ); ?></p>
+		<p><a class="button edit" id="bp-delete-cover-image" href="#" title="<?php esc_attr_e( 'Delete Cover Image', 'buddypress' ); ?>"><?php esc_html_e( 'Delete Group Cover Image', 'buddypress' ); ?></a></p>
+	<# } else { #>
+		<?php do_action( 'bp_attachments_cover_image_delete_template' ); ?>
+	<# } #>
+</script>
+
+<?php do_action( 'bp_attachments_cover_image_main_template' ); ?>
diff --git src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php
new file mode 100644
index 0000000..d59cb47
--- /dev/null
+++ src/bp-templates/bp-legacy/buddypress/members/single/cover-image-header.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * BuddyPress - Users Cover Image Header
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php
+
+/**
+ * Fires before the display of a member's header.
+ *
+ * @since BuddyPress (1.2.0)
+ */
+do_action( 'bp_before_member_header' ); ?>
+
+<a id="header-cover-image" href="<?php bp_displayed_user_link(); ?>"></a>
+
+<div id="item-header-cover-image">
+	<div id="item-header-avatar">
+		<a href="<?php bp_displayed_user_link(); ?>">
+
+			<?php bp_displayed_user_avatar( 'type=full' ); ?>
+
+		</a>
+	</div><!-- #item-header-avatar -->
+
+	<div id="item-header-content">
+
+		<?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
+			<h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
+		<?php endif; ?>
+
+		<div id="item-buttons">
+
+			<?php
+
+			/**
+			 * Fires in the member header actions section.
+			 *
+			 * @since BuddyPress (1.2.6)
+			 */
+			do_action( 'bp_member_header_actions' ); ?>
+
+		</div><!-- #item-buttons -->
+
+		<span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
+
+		<?php
+	
+		/**
+		 * Fires before the display of the member's header meta.
+		 *
+		 * @since BuddyPress (1.2.0)
+		 */
+		do_action( 'bp_before_member_header_meta' ); ?>
+	
+		<div id="item-meta">
+	
+			<?php if ( bp_is_active( 'activity' ) ) : ?>
+	
+				<div id="latest-update">
+	
+					<?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
+	
+				</div>
+	
+			<?php endif; ?>
+	
+			<?php
+	
+			 /**
+			  * Fires after the group header actions section.
+			  *
+			  * If you'd like to show specific profile fields here use:
+			  * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
+			  *
+			  * @since BuddyPress (1.2.0)
+			  */
+			 do_action( 'bp_profile_header_meta' );
+	
+			 ?>
+	
+		</div><!-- #item-meta -->
+
+	</div><!-- #item-header-content -->
+
+</div><!-- #item-header-cover-image -->
+
+<?php
+
+/**
+ * Fires after the display of a member's header.
+ *
+ * @since BuddyPress (1.2.0)
+ */
+do_action( 'bp_after_member_header' ); ?>
+
+<?php
+
+/** This action is documented in bp-templates/bp-legacy/buddypress/activity/index.php */
+do_action( 'template_notices' ); ?>
diff --git src/bp-templates/bp-legacy/buddypress/members/single/home.php src/bp-templates/bp-legacy/buddypress/members/single/home.php
index 6b9f04c..03a59cc 100644
--- src/bp-templates/bp-legacy/buddypress/members/single/home.php
+++ src/bp-templates/bp-legacy/buddypress/members/single/home.php
@@ -11,7 +11,16 @@
 
 	<div id="item-header" role="complementary">
 
-		<?php bp_get_template_part( 'members/single/member-header' ) ?>
+		<?php
+		/**
+		 * Since 2.4.0, we display the cover image header by default.
+		 */
+		if ( bp_is_active( 'xprofile', 'cover_image' ) ) :
+			bp_get_template_part( 'members/single/cover-image-header' );
+		else :
+			bp_get_template_part( 'members/single/member-header' );
+		endif;
+		?>
 
 	</div><!-- #item-header -->
 
diff --git src/bp-templates/bp-legacy/buddypress/members/single/profile.php src/bp-templates/bp-legacy/buddypress/members/single/profile.php
index 165cd17..f419718 100644
--- src/bp-templates/bp-legacy/buddypress/members/single/profile.php
+++ src/bp-templates/bp-legacy/buddypress/members/single/profile.php
@@ -38,6 +38,11 @@ do_action( 'bp_before_profile_content' ); ?>
 		bp_get_template_part( 'members/single/profile/change-avatar' );
 		break;
 
+	// Change Cover Image
+	case 'change-cover-image' :
+		bp_get_template_part( 'members/single/profile/change-cover-image' );
+		break;
+
 	// Compose
 	case 'public' :
 
diff --git src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php
new file mode 100644
index 0000000..a114aee
--- /dev/null
+++ src/bp-templates/bp-legacy/buddypress/members/single/profile/change-cover-image.php
@@ -0,0 +1,23 @@
+<h4><?php _e( 'Change Cover Image', 'buddypress' ); ?></h4>
+
+<?php
+
+/**
+ * Fires before the display of profile cover image upload content.
+ *
+ * @since BuddyPress (2.4.0)
+ */
+do_action( 'bp_before_profile_cover_image_upload_content' ); ?>
+
+<p><?php _e( 'Your Cover Image will be used to customize the header of your profile.', 'buddypress' ); ?></p>
+
+<?php bp_attachments_get_template_part( 'cover-images/index' ); ?>
+
+<?php
+
+/**
+ * Fires after the display of profile cover image upload content.
+ *
+ * @since BuddyPress (2.4.0)
+ */
+do_action( 'bp_after_profile_cover_image_upload_content' ); ?>
diff --git src/bp-templates/bp-legacy/css/buddypress.css src/bp-templates/bp-legacy/css/buddypress.css
index aca34c6..c6712ff 100644
--- src/bp-templates/bp-legacy/css/buddypress.css
+++ src/bp-templates/bp-legacy/css/buddypress.css
@@ -19,6 +19,7 @@ Hello, this is the BuddyPress Legacy stylesheet.
 	3.6 - Ajax Loading
 	3.7 - Topics and Tables - Forums and General
 	3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+		3.8.1 - Cover Image
 	3.9 - Private Messaging Threads
 	3.10 - Extended Profiles
 	3.11 - Widgets
@@ -1168,6 +1169,7 @@ a.bp-title-button {
 }
 #buddypress div#item-header {
 	overflow: hidden;
+	position: relative;
 }
 #buddypress div#item-header div#item-header-content {
 	float: left;
@@ -1393,6 +1395,31 @@ body.activity-permalink #buddypress ul.item-list li.activity-item {
 	list-style: none;
 }
 
+/*--------------------------------------------------------------
+3.8.1 - Cover Image
+--------------------------------------------------------------*/
+
+#buddypress #header-cover-image {
+	background-color: #c5c5c5;
+	background-position: center top;
+	background-repeat: no-repeat;
+	background-size: cover;
+	border: 0;
+	display: block;
+	left: 0;
+	margin: 0;
+	padding: 0;
+	position: absolute;
+	top: 0;
+	width: 100%;
+	z-index: 1;
+}
+
+#buddypress #item-header-cover-image {
+	padding: 0 1em;
+	position: relative;
+	z-index: 999;
+}
 
 /*--------------------------------------------------------------
 3.9 - Private Messaging Threads
diff --git src/bp-templates/bp-legacy/css/twentyfifteen.css src/bp-templates/bp-legacy/css/twentyfifteen.css
index 7c9eabf..d56436c 100644
--- src/bp-templates/bp-legacy/css/twentyfifteen.css
+++ src/bp-templates/bp-legacy/css/twentyfifteen.css
@@ -957,7 +957,7 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 
 .bp-user #buddypress #item-header #item-header-avatar img.avatar,
 .bp-user #buddypress #item-header #item-header-avatar a {
-	border-bottom: 0;
+	border-bottom-color: #fff;
 	display: inline-block;
 	float: none;
 }
@@ -967,10 +967,8 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 		float: left;
 		width: 20%;
 	}
-	.bp-user #buddypress #item-header #item-header-avatar img.avatar,
+
 	.bp-user #buddypress #item-header #item-header-avatar a {
-		float: left;
-		width: 100%;
 	}
 	.bp-user #buddypress #item-header #item-header-content {
 		float: right;
diff --git src/bp-templates/bp-legacy/css/twentyfifteen.scss src/bp-templates/bp-legacy/css/twentyfifteen.scss
index 22c7eba..267a0d1 100644
--- src/bp-templates/bp-legacy/css/twentyfifteen.scss
+++ src/bp-templates/bp-legacy/css/twentyfifteen.scss
@@ -1199,7 +1199,6 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 				text-align: center;
 				width: 100%;
 
-				img.avatar,
 				a {
 					border-bottom: 0;
 					display: inline-block;
diff --git src/bp-templates/bp-legacy/css/twentyfourteen.css src/bp-templates/bp-legacy/css/twentyfourteen.css
index b00e3fe..833cbfa 100644
--- src/bp-templates/bp-legacy/css/twentyfourteen.css
+++ src/bp-templates/bp-legacy/css/twentyfourteen.css
@@ -782,9 +782,6 @@ body.activity-permalink #buddypress {
 		text-align: left;
 		width: 20%;
 	}
-	.bp-user #buddypress #item-header #item-header-avatar img {
-		margin: 0;
-	}
 	.bp-user #buddypress #item-header #item-header-content {
 		float: right;
 		width: 78%;
diff --git src/bp-templates/bp-legacy/css/twentyfourteen.scss src/bp-templates/bp-legacy/css/twentyfourteen.scss
index 8b9872f..dcf6ed7 100644
--- src/bp-templates/bp-legacy/css/twentyfourteen.scss
+++ src/bp-templates/bp-legacy/css/twentyfourteen.scss
@@ -1100,8 +1100,6 @@ body.activity-permalink {
 				overflow: hidden;
 				text-align: left;
 				width: 20%;
-
-				img {margin: 0;}
 			}
 
 			#item-header-content {
diff --git src/bp-templates/bp-legacy/css/twentythirteen.css src/bp-templates/bp-legacy/css/twentythirteen.css
index d2eb95e..0405201 100644
--- src/bp-templates/bp-legacy/css/twentythirteen.css
+++ src/bp-templates/bp-legacy/css/twentythirteen.css
@@ -943,7 +943,6 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 
 .bp-user #buddypress #item-header #item-header-avatar img.avatar,
 .bp-user #buddypress #item-header #item-header-avatar a {
-	border-bottom: 0;
 	display: inline-block;
 	float: none;
 }
@@ -953,10 +952,8 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 		float: left;
 		width: 20%;
 	}
-	.bp-user #buddypress #item-header #item-header-avatar img.avatar,
+
 	.bp-user #buddypress #item-header #item-header-avatar a {
-		float: left;
-		width: 100%;
 	}
 	.bp-user #buddypress #item-header #item-header-content {
 		float: right;
diff --git src/bp-templates/bp-legacy/css/twentythirteen.scss src/bp-templates/bp-legacy/css/twentythirteen.scss
index 427a724..17a26f0 100644
--- src/bp-templates/bp-legacy/css/twentythirteen.scss
+++ src/bp-templates/bp-legacy/css/twentythirteen.scss
@@ -1267,10 +1267,8 @@ http://codex.buddypress.org/themes/buddypress-companion-stylesheets/
 					float: left;
 					width: 20%;
 
-					img.avatar,
 					a {
 						float: left;
-						width: 100%;
 					}
 				}
 
diff --git src/bp-xprofile/bp-xprofile-loader.php src/bp-xprofile/bp-xprofile-loader.php
index a38b21b..79364d3 100644
--- src/bp-xprofile/bp-xprofile-loader.php
+++ src/bp-xprofile/bp-xprofile-loader.php
@@ -226,6 +226,19 @@ class BP_XProfile_Component extends BP_Component {
 				'position'        => 30,
 				'user_has_access' => $access
 			);
+
+			// Change Cover image
+			if ( ! bp_disable_avatar_uploads() && bp_is_active( $this->id, 'cover_image' ) ) {
+				$sub_nav[] = array(
+					'name'            => _x( 'Change Cover Image', 'Profile header sub menu', 'buddypress' ),
+					'slug'            => 'change-cover-image',
+					'parent_url'      => $profile_link,
+					'parent_slug'     => $slug,
+					'screen_function' => 'xprofile_screen_change_cover_image',
+					'position'        => 40,
+					'user_has_access' => $access
+				);
+			}
 		}
 
 		// The Settings > Profile nav item can only be set up after
@@ -314,8 +327,16 @@ class BP_XProfile_Component extends BP_Component {
 					'title'  => _x( 'Change Profile Photo', 'My Account Profile sub nav', 'buddypress' ),
 					'href'   => trailingslashit( $profile_link . 'change-avatar' )
 				);
-			}
 
+				if ( ! bp_disable_avatar_uploads() && bp_is_active( $this->id, 'cover_image' ) ) {
+					$wp_admin_nav[] = array(
+						'parent' => 'my-account-' . $this->id,
+						'id'     => 'my-account-' . $this->id . '-change-cover-image',
+						'title'  => _x( 'Change Cover Image', 'My Account Profile sub nav', 'buddypress' ),
+						'href'   => trailingslashit( $profile_link . 'change-cover-image' )
+					);
+				}
+			}
 		}
 
 		parent::setup_admin_bar( $wp_admin_nav );
diff --git src/bp-xprofile/bp-xprofile-screens.php src/bp-xprofile/bp-xprofile-screens.php
index afb4604..6650f00 100644
--- src/bp-xprofile/bp-xprofile-screens.php
+++ src/bp-xprofile/bp-xprofile-screens.php
@@ -292,6 +292,37 @@ function xprofile_screen_change_avatar() {
 }
 
 /**
+ * Displays the change cover image page.
+ *
+ * @package BuddyPress XProfile
+ *
+ * @since BuddyPress (2.4.0)
+ */
+function xprofile_screen_change_cover_image() {
+
+	// Bail if not the correct screen
+	if ( ! bp_is_my_profile() && ! bp_current_user_can( 'bp_moderate' ) ) {
+		return false;
+	}
+
+	/**
+	 * Fires right before the loading of the XProfile change cover image screen template file.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 */
+	do_action( 'xprofile_screen_change_cover_image' );
+
+	/**
+	 * Filters the template to load for the XProfile cover image screen.
+	 *
+	 * @since BuddyPress (2.4.0)
+	 *
+	 * @param string $template Path to the XProfile cover image template to load.
+	 */
+	bp_core_load_template( apply_filters( 'xprofile_template_cover_image', 'members/single/home' ) );
+}
+
+/**
  * Show the xprofile settings template
  *
  * @since BuddyPress (2.0.0)
