diff --git src/bp-core/admin/bp-core-admin-types.php src/bp-core/admin/bp-core-admin-types.php
new file mode 100644
index 000000000..6b8db3f7a
--- /dev/null
+++ src/bp-core/admin/bp-core-admin-types.php
@@ -0,0 +1,298 @@
+<?php
+/**
+ * BuddyPress Types Admin functions.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @since 7.0.0
+ */
+
+// Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Get default values for the taxonomy registered metadata.
+ *
+ * @since 7.0.0
+ *
+ * @param string $type_taxonomy The type's taxonomy name.
+ * @return array                Default values for the taxonomy registered metadata.
+ */
+function bp_core_admin_get_type_default_meta_values( $type_taxonomy ) {
+	$metadata_schema = bp_get_type_metadata_schema( false, $type_taxonomy );
+	$metadata        = wp_list_pluck( $metadata_schema, 'type' );
+
+	// Set default values according to their schema type.
+	foreach ( $metadata as $meta_key => $meta_value ) {
+		if ( in_array( $meta_value, array( 'boolean', 'integer' ), true ) ) {
+			$metadata[ $meta_key ] = 0;
+		} else {
+			$metadata[ $meta_key ] = '';
+		}
+	}
+
+	return $metadata;
+}
+
+/**
+ * Insert a new type into the database.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $args {
+ *     Array of arguments describing the object type.
+ *
+ *     @type string $taxonomy   The Type's taxonomy. Required.
+ *     @type string $bp_type_id Unique string identifier for the member type. Required.
+ *     @see keys of the array returned by bp_get_type_metadata_schema() for the other arguments.
+ * }
+ * @return integer|WP_Error The Type's term ID on success. A WP_Error object otherwise.
+ */
+function bp_core_admin_insert_type( $args = array() ) {
+	$default_args = array(
+		'taxonomy'   => '',
+		'bp_type_id' => '',
+	);
+
+	$args = array_map( 'wp_unslash', $args );
+	$args = bp_parse_args(
+		$args,
+		$default_args,
+		'admin_insert_type'
+	);
+
+	if ( ! $args['bp_type_id'] || ! $args['taxonomy'] ) {
+		 return new WP_Error(
+			 'invalid_type_taxonomy',
+			 __( 'The Type ID value is missing', 'buddypress' ),
+			 array(
+				'message' => 1,
+			 )
+		);
+	}
+
+	$type_id       = sanitize_title( $args['bp_type_id'] );
+	$type_taxonomy = sanitize_key( $args['taxonomy'] );
+
+	/**
+	 * Filter here to check for an already existing type.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param boolean $value   True if the type exists. False otherwise.
+	 * @param string  $type_id The Type's ID.
+	 */
+	$type_exists = apply_filters( "{$type_taxonomy}_check_existing_type", false, $type_id );
+
+	if ( false !== $type_exists ) {
+		return new WP_Error(
+			'type_already_exists',
+			__( 'The Type already exists', 'buddypress' ),
+			array(
+			   'message' => 5,
+			)
+	   );
+	}
+
+	// Get defaulte values for metadata.
+	$metadata = bp_core_admin_get_type_default_meta_values( $type_taxonomy );
+
+	// Validate metadata
+	$metas = array_filter( array_intersect_key( $args, $metadata ) );
+
+	// Insert the Type into the database.
+	$type_term_id = bp_insert_term(
+		$type_id,
+		$type_taxonomy,
+		array(
+			'slug'  => $type_id,
+			'metas' => $metas,
+		)
+	);
+
+	if ( is_wp_error( $type_term_id ) ) {
+		$type_term_id->add_data(
+			array(
+				'message' => 3,
+			)
+		);
+
+		return $type_term_id;
+	}
+
+	/**
+	 * Hook here to add code once the type has been inserted.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param integer $type_term_id  The Type's term_ID.
+	 * @param string  $type_taxonomy The Type's taxonomy name.
+	 * @param string  $type_id       The Type's ID.
+	 */
+	do_action( 'bp_type_inserted', $type_term_id, $type_taxonomy, $type_id );
+
+	// Finally return the inserted Type's term ID.
+	return $type_term_id;
+}
+
+/**
+ * Update a type into the database.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $args {
+ *     Array of arguments describing the object type.
+ *
+ *     @type string  $taxonomy     The Type's taxonomy. Required.
+ *     @type integer $type_term_id The Type's term ID. Required.
+ *     @see keys of the array returned by bp_get_type_metadata_schema() for the other arguments.
+ * }
+ * @return boolean|WP_Error True on success. A WP_Error object otherwise.
+ */
+function bp_core_admin_update_type( $args = array() ) {
+	$default_args = array(
+		'taxonomy'     => '',
+		'type_term_id' => 0,
+	);
+
+	$args = array_map( 'wp_unslash', $args );
+	$args = bp_parse_args(
+		$args,
+		$default_args,
+		'admin_update_type'
+	);
+
+	if ( ! $args['type_term_id'] || ! $args['taxonomy'] ) {
+		 return new WP_Error(
+			 'invalid_type_taxonomy',
+			 __( 'The Term Type ID value is missing', 'buddypress' ),
+			 array(
+				'message' => 10,
+			)
+		);
+	}
+
+	$type_term_id  = (int) $args['type_term_id'];
+	$type_taxonomy = sanitize_key( $args['taxonomy'] );
+
+	// Get defaulte values for metadata.
+	$metadata  = bp_core_admin_get_type_default_meta_values( $type_taxonomy );
+
+	// Merge customs with defaults.
+	$metas = wp_parse_args( $args, $metadata );
+
+	// Validate metadata
+	$metas = array_intersect_key( $metas, $metadata );
+
+	foreach ( $metas as $meta_key => $meta_value ) {
+		if ( '' === $meta_value ) {
+			delete_term_meta( $type_term_id, $meta_key );
+		} else {
+			update_term_meta( $type_term_id, $meta_key, $meta_value );
+		}
+	}
+
+	/**
+	 * Hook here to add code once the type has been updated.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param integer $type_term_id  The Type's term_ID.
+	 * @param string  $type_taxonomy The Type's taxonomy name.
+	 */
+	do_action( 'bp_type_updated', $type_term_id, $type_taxonomy );
+
+	// Finally informs about the successfull update.
+	return true;
+}
+
+/**
+ * Delete a type from the database.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $args {
+ *     Array of arguments describing the object type.
+ *
+ *     @type string  $taxonomy     The Type's taxonomy. Required.
+ *     @type integer $type_term_id The Type's term ID. Required.
+ * }
+ * @return boolean|WP_Error True on success. A WP_Error object otherwise.
+ */
+function bp_core_admin_delete_type( $args = array() ) {
+	$default_args = array(
+		'taxonomy'     => '',
+		'type_term_id' => 0,
+	);
+
+	$args = array_map( 'wp_unslash', $args );
+	$args = bp_parse_args(
+		$args,
+		$default_args,
+		'admin_delete_type'
+	);
+
+	if ( ! $args['type_term_id'] || ! $args['taxonomy'] ) {
+		 return new WP_Error(
+			 'invalid_type_taxonomy',
+			 __( 'The Term Type ID value is missing', 'buddypress' ),
+			 array(
+				'message' => 10,
+			)
+		);
+	}
+
+	$type_term_id  = (int) $args['type_term_id'];
+	$type_taxonomy = sanitize_key( $args['taxonomy'] );
+	$type_term     = bp_get_term_by( 'id', $type_term_id, $type_taxonomy );
+
+	if ( ! $type_term ) {
+		return new WP_Error(
+			'type_doesnotexist',
+			__( 'The type was not deleted: it does not exist.', 'buddypress' ),
+			array(
+			   'message' => 6,
+			)
+		);
+	}
+
+	/** This filter is documented in bp-core/classes/class-bp-admin-types.php */
+	$registered_by_code_types = apply_filters( "{$type_taxonomy}_registered_by_code", array() );
+
+	if ( isset( $registered_by_code_types[ $type_term->name ] ) ) {
+		return new WP_Error(
+			'type_register_by_code',
+			__( 'This type is registered using code, deactivate the plugin or remove the custom code before trying to delete it again.', 'buddypress' ),
+			array(
+			   'message' => 7,
+			)
+		);
+	}
+
+	$deleted = bp_delete_term( $type_term_id, $type_taxonomy );
+
+	if ( true !== $deleted ) {
+		return new WP_Error(
+			'type_not_deleted',
+			__( 'There was an error while trying to delete this type.', 'buddypress' ),
+			array(
+			   'message' => 8,
+			)
+		);
+	}
+
+	/**
+	 * Hook here to add code once the type has been deleted.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param integer $type_term_id  The Type's term_ID.
+	 * @param string  $type_taxonomy The Type's taxonomy name.
+	 */
+	do_action( 'bp_type_deleted', $type_term_id, $type_taxonomy );
+
+	// Finally informs about the successfull delete.
+	return true;
+}
diff --git src/bp-core/admin/js/types-admin.js src/bp-core/admin/js/types-admin.js
new file mode 100644
index 000000000..077fdcf3d
--- /dev/null
+++ src/bp-core/admin/js/types-admin.js
@@ -0,0 +1,41 @@
+( function() {
+	var bpTypesCustomizeForm = function() {
+		if ( document.querySelector( '#addtag input[name="post_type"]' ) ) {
+			document.querySelector( '#addtag input[name="post_type"]' ).remove();
+		}
+
+		if ( document.querySelectorAll( '.form-field' ) ) {
+			document.querySelectorAll( '.form-field' ).forEach( function( element ) {
+				if ( -1 === element.classList.value.indexOf( 'bp-types-form' ) ) {
+					element.remove();
+				}
+			} );
+		}
+
+		if ( document.querySelector( '#bp_type_has_directory' ) ) {
+			if ( true === document.querySelector( '#bp_type_has_directory' ).checked ) {
+				document.querySelector( '.term-bp_type_directory_slug-wrap' ).classList.add( 'bp-set-directory-slug' );
+			}
+
+			document.querySelector( '#bp_type_has_directory' ).addEventListener( 'change', function( event ) {
+				if ( true === event.target.checked ) {
+					document.querySelector( '.term-bp_type_directory_slug-wrap' ).classList.add( 'bp-set-directory-slug' );
+					document.querySelector( '#bp_type_directory_slug' ).removeAttribute( 'disabled' );
+				} else {
+					document.querySelector( '.term-bp_type_directory_slug-wrap' ).classList.remove( 'bp-set-directory-slug' );
+					document.querySelector( '#bp_type_directory_slug' ).setAttribute( 'disabled', 'disabled' );
+				}
+			} );
+		}
+
+		if ( document.querySelector( '#delete-link' ) ) {
+			document.querySelector( '#delete-link' ).remove();
+		}
+	};
+
+	if ( 'loading' === document.readyState ) {
+		document.addEventListener( 'DOMContentLoaded', bpTypesCustomizeForm );
+	} else {
+		bpTypesCustomizeForm;
+	}
+} )();
diff --git src/bp-core/bp-core-actions.php src/bp-core/bp-core-actions.php
index 89296dd79..caf628b97 100644
--- src/bp-core/bp-core-actions.php
+++ src/bp-core/bp-core-actions.php
@@ -82,9 +82,10 @@ add_action( 'bp_init', 'bp_add_rewrite_rules',       30 );
 add_action( 'bp_init', 'bp_add_permastructs',        40 );
 
 /**
- * The bp_register_taxonomies hook - Attached to 'bp_init' @ priority 2 above.
+ * The bp_register_taxonomies hooks - Attached to 'bp_init' @ priority 2 above.
  */
 add_action( 'bp_register_taxonomies', 'bp_register_member_types' );
+add_action( 'bp_register_taxonomies', 'bp_register_type_metadata', 20 );
 
 /**
  * Late includes.
diff --git src/bp-core/bp-core-cache.php src/bp-core/bp-core-cache.php
index 2868eb87f..12c674241 100644
--- src/bp-core/bp-core-cache.php
+++ src/bp-core/bp-core-cache.php
@@ -390,3 +390,28 @@ function bp_invitations_reset_cache_incrementor() {
 }
 add_action( 'bp_invitation_after_save', 'bp_invitations_reset_cache_incrementor' );
 add_action( 'bp_invitation_after_delete', 'bp_invitations_reset_cache_incrementor' );
+
+/**
+ * Add a cache group for Database object types.
+ *
+ * @since 7.0.0
+ */
+function bp_set_object_type_terms_cache_group() {
+	wp_cache_add_global_groups( 'bp_object_terms' );
+}
+add_action( 'bp_setup_cache_groups', 'bp_set_object_type_terms_cache_group' );
+
+/**
+ * Clear the Database object types cache.
+ *
+ * @since 7.0.0
+ *
+ * @param int $type_id The Type's term ID.
+ * @param string $taxonomy The Type's taxonomy name.
+ */
+function bp_clear_object_type_terms_cache( $type_id = 0, $taxonomy = '' ) {
+	wp_cache_delete( $taxonomy, 'bp_object_terms' );
+}
+add_action( 'bp_type_inserted', 'bp_clear_object_type_terms_cache' );
+add_action( 'bp_type_updated', 'bp_clear_object_type_terms_cache' );
+add_action( 'bp_type_deleted', 'bp_clear_object_type_terms_cache' );
diff --git src/bp-core/bp-core-dependency.php src/bp-core/bp-core-dependency.php
index cb3a3f4f5..91d2566b3 100644
--- src/bp-core/bp-core-dependency.php
+++ src/bp-core/bp-core-dependency.php
@@ -95,6 +95,21 @@ function bp_register_taxonomies() {
 	do_action( 'bp_register_taxonomies' );
 }
 
+/**
+ * Fire the 'bp_register_type_metadata' action, where plugins should register metadata for their custom BuddyPress types.
+ *
+ * @since 7.0.0
+ */
+function bp_register_type_metadata() {
+
+	/**
+	 * Fires inside the 'bp_register_type_metadata' function, where plugins should register metadata for their custom BuddyPress types.
+	 *
+	 * @since 7.0.0
+	 */
+	do_action( 'bp_register_type_metadata' );
+}
+
 /**
  * Fire the 'bp_register_post_types' action, where plugins should register post types.
  *
diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
index c1481135e..74b6830a3 100644
--- src/bp-core/bp-core-functions.php
+++ src/bp-core/bp-core-functions.php
@@ -2936,6 +2936,41 @@ function bp_get_email_post_type_supports() {
 
 /** Taxonomies *****************************************************************/
 
+/**
+ * Returns the BP Taxonomy common arguments.
+ *
+ * @since 7.0.0
+ *
+ * @return array The BP Taxonomy common arguments.
+ */
+function bp_get_taxonomy_common_args() {
+	return array(
+		'public'        => false,
+		'show_in_rest'  => false,
+		'query_var'     => false,
+		'rewrite'       => false,
+		'show_in_menu'  => false,
+		'show_tagcloud' => false,
+		'show_ui'       => bp_is_root_blog() && bp_current_user_can( 'bp_moderate' ),
+	);
+}
+
+/**
+ * Returns the BP Taxonomy common labels.
+ *
+ * @since 7.0.0
+ *
+ * @return array The BP Taxonomy common labels.
+ */
+function bp_get_taxonomy_common_labels() {
+	return array(
+		'bp_type_name'           => _x( 'Name', 'BP Type name label', 'buddypress' ),
+		'bp_type_singular_name'  => _x( 'Singular name', 'BP Type singular name label', 'buddypress' ),
+		'bp_type_has_directory'  => _x( 'Add Type-Filtered Directory View', 'BP Type has directory checkbox label', 'buddypress' ),
+		'bp_type_directory_slug' => _x( 'Custom type directory slug', 'BP Type slug label', 'buddypress' ),
+	);
+}
+
 /**
  * Output the name of the email type taxonomy.
  *
@@ -2998,6 +3033,229 @@ function bp_get_email_tax_type_labels() {
 	) );
 }
 
+/**
+ * Return arguments used by the email type taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @return array
+ */
+function bp_get_email_tax_type_args() {
+
+	/**
+	 * Filters emails type taxonomy args.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $value Associative array (key => arg).
+	 */
+	return apply_filters(
+		'bp_register_email_tax_type',
+		array_merge(
+			array(
+				'description'   => _x( 'BuddyPress email types', 'email type taxonomy description', 'buddypress' ),
+				'labels'        => bp_get_email_tax_type_labels(),
+				'meta_box_cb'   => 'bp_email_tax_type_metabox',
+			),
+			bp_get_taxonomy_common_args()
+		)
+	);
+}
+
+/**
+ * Returns the default BuddyPress type metadata schema.
+ *
+ * @since 7.0.0
+ *
+ * @param  boolean $suppress_filters Whether to suppress filters. Default `false`.
+ * @param  string  $type_taxonomy    Optional. the Type's taxonomy name.
+ * @return array                     The default BuddyPress type metadata schema.
+ */
+function bp_get_type_metadata_schema( $suppress_filters = false, $type_taxonomy = '' ) {
+	$schema = array(
+		'bp_type_name' => array(
+			'description'       => __( 'The name of your type, at the plural form.', 'buddypress' ),
+			'type'              => 'string',
+			'single'            => true,
+			'sanitize_callback' => 'sanitize_text_field',
+		),
+		'bp_type_singular_name' => array(
+			'description'       => __( 'The name of your type, at the singular form.', 'buddypress' ),
+			'type'              => 'string',
+			'single'            => true,
+			'sanitize_callback' => 'sanitize_text_field',
+		),
+		'bp_type_has_directory' => array(
+			'description'       => __( 'Add a list of members matching the member type available on the Members Directory page (e.g. site.url/members/type/teacher/).', 'buddypress' ),
+			'type'              => 'boolean',
+			'single'            => true,
+			'sanitize_callback' => 'absint',
+		),
+		'bp_type_directory_slug' => array(
+			'label'             => __( 'Custom type directory slug', 'buddypress' ),
+			'description'       => __( 'If you want to use a slug that is different from the Member Type ID above, enter it here.', 'buddypress' ),
+			'type'              => 'string',
+			'single'            => true,
+			'sanitize_callback' => 'sanitize_title',
+		),
+	);
+
+	if ( true === $suppress_filters ) {
+		return $schema;
+	}
+
+	/**
+	 * Filter here to add new meta to the BuddyPress type metadata.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array  $schema        Associative array (name => arguments).
+	 * @param string $type_taxonomy The Type's taxonomy name.
+	 */
+	return apply_filters( 'bp_get_type_metadata_schema', $schema, $type_taxonomy );
+}
+
+/**
+ * Registers a meta key for BuddyPress types.
+ *
+ * @since 7.0.0
+ *
+ * @param string $type_tax The BuddyPress type taxonomy.
+ * @param string $meta_key The meta key to register.
+ * @param array  $args     Data used to describe the meta key when registered. See
+ *                         {@see register_meta()} for a list of supported arguments.
+ * @return bool True if the meta key was successfully registered, false if not.
+ */
+function bp_register_type_meta( $type_tax, $meta_key, array $args ) {
+	$taxonomies = wp_list_pluck( bp_get_default_taxonomies(), 'component' );
+
+	if ( ! isset( $taxonomies[ $type_tax ] ) ) {
+		return false;
+	}
+
+	// register_term_meta() was introduced in WP 4.9.8.
+	if ( ! function_exists( 'register_term_meta' ) ) {
+		$args['object_subtype'] = $type_tax;
+
+		return register_meta( 'term', $meta_key, $args );
+	}
+
+	return register_term_meta( $type_tax, $meta_key, $args );
+}
+
+/**
+ * Update a list of metadata for a given type ID and a given taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @param  integer $type_id    The database ID of the BP Type.
+ * @param  string  $taxonomy   The BP Type taxonomy.
+ * @param  array   $type_metas An associative array (meta_key=>meta_value).
+ * @return boolean             False on failure. True otherwise.
+ */
+function bp_update_type_metadata( $type_id = 0, $taxonomy = '', $type_metas = array() ) {
+	if ( ! $type_id || ! $taxonomy || ! is_array( $type_metas ) ) {
+		return false;
+	}
+
+	foreach ( $type_metas as $meta_key => $meta_value ) {
+		if ( ! registered_meta_key_exists( 'term', $meta_key, $taxonomy ) ) {
+			continue;
+		}
+
+		update_term_meta( $type_id, $meta_key, $meta_value );
+	}
+
+	return true;
+}
+
+/**
+ * Get types for a given BP Taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @param string $taxonomy The taxonomy to transform terms in types for.
+ * @param array  $types    Existing types to merge with the types found into the database.
+ *                         For instance this function is used internally to merge Group/Member
+ *                         types registered using code with the ones created by the administrator
+ *                         from the Group/Member types Administration screen. If not provided, only
+ *                         Types created by the administrator will be returned.
+ *                         Optional.
+ * @return array           The types of the given taxonomy.
+ */
+function bp_get_taxonomy_types( $taxonomy = '', $types = array() ) {
+	if ( ! $taxonomy ) {
+		return $types;
+	}
+
+	$db_types = wp_cache_get( $taxonomy, 'bp_object_terms' );
+
+	if ( ! $db_types ) {
+		$terms = bp_get_terms(
+			array(
+				'taxonomy' => $taxonomy,
+			)
+		);
+
+		if ( ! is_array( $terms ) ) {
+			return $types;
+		}
+
+		$type_metadata = array_keys( get_registered_meta_keys( 'term', $taxonomy ) );
+
+		foreach ( $terms as $term ) {
+			$type_name                      = $term->name;
+			$db_types[ $type_name ]         = new stdClass();
+			$db_types[ $type_name ]->db_id  = $term->term_id;
+			$db_types[ $type_name ]->labels = array();
+			$db_types[ $type_name ]->name   = $type_name;
+
+			if ( $type_metadata ) {
+				foreach ( $type_metadata as $meta_key ) {
+					$type_key = str_replace( 'bp_type_', '', $meta_key );
+					if ( in_array( $type_key, array( 'name', 'singular_name' ), true ) ) {
+						$db_types[ $type_name ]->labels[ $type_key ] = get_term_meta( $term->term_id, $meta_key, true );
+					} else {
+						$db_types[ $type_name ]->{$type_key} = get_term_meta( $term->term_id, $meta_key, true );
+					}
+				}
+			}
+		}
+
+		wp_cache_set( $taxonomy, $db_types, 'bp_object_terms' );
+	}
+
+	if ( is_array( $db_types ) ) {
+		foreach ( $db_types as $db_type_name => $db_type ) {
+			// Override props of registered by code types if customized by the admun user.
+			if ( isset( $types[ $db_type_name ] ) && isset( $types[ $db_type_name ]->code ) && $types[ $db_type_name ]->code ) {
+				// Merge Labels.
+				if ( $db_type->labels ) {
+					foreach ( $db_type->labels as $key_label => $value_label ) {
+						if ( '' !== $value_label ) {
+							$types[ $db_type_name ]->labels[ $key_label ] = $value_label;
+						}
+					}
+				}
+
+				// Merge other properties.
+				foreach ( get_object_vars( $types[ $db_type_name ] ) as $key_prop => $value_prop ) {
+					if ( 'labels' === $key_prop || 'name' === $key_prop ) {
+						continue;
+					}
+
+					if ( isset( $db_type->{$key_prop} ) && '' !== $db_type->{$key_prop} ) {
+						$types[ $db_type_name  ]->{$key_prop} = $db_type->{$key_prop};
+					}
+				}
+
+				unset( $db_types[ $db_type_name ] );
+			}
+		}
+	}
+
+	return array_merge( $types, (array) $db_types );
+}
 
 /** Email *****************************************************************/
 
diff --git src/bp-core/bp-core-taxonomy.php src/bp-core/bp-core-taxonomy.php
index 14334e00d..69932c953 100644
--- src/bp-core/bp-core-taxonomy.php
+++ src/bp-core/bp-core-taxonomy.php
@@ -14,33 +14,58 @@
 // Exit if accessed directly.
 defined( 'ABSPATH' ) || exit;
 
+/**
+ * Returns default BuddyPress taxonomies.
+ *
+ * @since 7.0.0
+ *
+ * @return array The BuddyPress default taxonomies.
+ */
+function bp_get_default_taxonomies() {
+	$taxonomies = array(
+		// Member Type.
+		bp_get_member_type_tax_name() => array(
+			'object'    => 'user',
+			'component' => 'members',
+			'args'      => bp_get_member_type_tax_args(),
+		),
+		// Email type.
+		bp_get_email_tax_type()       => array(
+			'object'    => bp_get_email_post_type(),
+			'component' => 'core',
+			'args'      => bp_get_email_tax_type_args(),
+		),
+	);
+
+	/**
+	 * This filter should only be used by built-in BuddyPress Components.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $taxonomies The taxonomy arguments used for WordPress registration.
+	 */
+	return apply_filters( 'bp_get_default_taxonomies', $taxonomies );
+}
+
 /**
  * Register our default taxonomies.
  *
  * @since 2.2.0
  */
 function bp_register_default_taxonomies() {
-	// Member Type.
-	register_taxonomy( bp_get_member_type_tax_name(), 'user', array(
-		'public' => false,
-	) );
-
-	// Email type.
-	register_taxonomy(
-		bp_get_email_tax_type(),
-		bp_get_email_post_type(),
-		apply_filters( 'bp_register_email_tax_type', array(
-			'description'   => _x( 'BuddyPress email types', 'email type taxonomy description', 'buddypress' ),
-			'labels'        => bp_get_email_tax_type_labels(),
-			'meta_box_cb'   => 'bp_email_tax_type_metabox',
-			'public'        => false,
-			'query_var'     => false,
-			'rewrite'       => false,
-			'show_in_menu'  => false,
-			'show_tagcloud' => false,
-			'show_ui'       => bp_is_root_blog() && bp_current_user_can( 'bp_moderate' ),
-		) )
-	);
+	$taxonomies = bp_get_default_taxonomies();
+
+	foreach ( $taxonomies as $taxonomy_name => $taxonomy_params ) {
+		if ( ! isset( $taxonomy_params['object'] ) || ! isset( $taxonomy_params['args'] ) ) {
+			continue;
+		}
+
+		register_taxonomy(
+			$taxonomy_name,
+			$taxonomy_params['object'],
+			$taxonomy_params['args']
+		);
+	}
 }
 add_action( 'bp_register_taxonomies', 'bp_register_default_taxonomies' );
 
@@ -277,3 +302,201 @@ function bp_get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filt
 
 	return $term;
 }
+
+/**
+ * Add a new taxonomy term to the database.
+ *
+ * @since 7.0.0
+ *
+ * @param string $term     The BP term name to add.
+ * @param string $taxonomy The BP taxonomy to which to add the BP term.
+ * @param array  $args {
+ *     Optional. Array of arguments for inserting a BP term.
+ *     @type string $description The term description. Default empty string.
+ *     @type string $slug        The term slug to use. Default empty string.
+ *     @type array  $metas       The term metas to add. Default empty array.
+ * }
+ * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`,
+ *                        WP_Error otherwise.
+ */
+function bp_insert_term( $term, $taxonomy = '', $args = array() ) {
+	if ( ! taxonomy_exists( $taxonomy ) ) {
+		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.', 'buddypress' ) );
+	}
+
+	$site_id = bp_get_taxonomy_term_site_id( $taxonomy );
+
+	$switched = false;
+	if ( $site_id !== get_current_blog_id() ) {
+		switch_to_blog( $site_id );
+		bp_register_taxonomies();
+		$switched = true;
+	}
+
+	$term_metas = array();
+	if ( isset( $args['metas'] ) ) {
+		$term_metas = (array) $args['metas'];
+		unset( $args['metas'] );
+	}
+
+	/**
+	 * Fires before a BP Term is added to the database.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param string $term     The BP term name to add.
+	 * @param string $taxonomy The BP taxonomy to which to add the term.
+	 * @param array  $args     Array of arguments for inserting a BP term.
+	 */
+	do_action( 'bp_before_insert_term', $term, $taxonomy, $args );
+
+	$tt_id = wp_insert_term( $term, $taxonomy, $args );
+
+	if ( is_wp_error( $tt_id ) ) {
+		return $tt_id;
+	}
+
+	$term_id = reset( $tt_id );
+
+	if ( $term_metas ) {
+		bp_update_type_metadata( $term_id, $taxonomy, $term_metas );
+	}
+
+	if ( $switched ) {
+		restore_current_blog();
+	}
+
+	/**
+	 * Fires when taxonomy terms have been set on BuddyPress objects.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array  $tt_ids    An array containing the `term_id` and `term_taxonomy_id`.
+	 * @param string $taxonomy  Taxonomy name.
+	 * @param array  $term_metas The term metadata.
+	 */
+	do_action( 'bp_insert_term', $tt_id, $taxonomy, $term_metas );
+
+	return $tt_id;
+}
+
+/**
+ * Get taxonomy BP Terms from the database.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $args {
+ *     Array of arguments to query BP Terms.
+ *     @see `get_terms()` for full description of arguments in case of a member type.
+ * }
+ * @return array The list of terms matching arguments.
+ */
+function bp_get_terms( $args = array() ) {
+	$args = bp_parse_args(
+		$args,
+		array(
+			'taxonomy'   => '',
+			'number'     => '',
+			'hide_empty' => false,
+		),
+		'get_terms'
+	);
+
+	if ( ! $args['taxonomy'] ) {
+		return array();
+	}
+
+	$site_id = bp_get_taxonomy_term_site_id( $args['taxonomy'] );
+
+	$switched = false;
+	if ( $site_id !== get_current_blog_id() ) {
+		switch_to_blog( $site_id );
+		bp_register_taxonomies();
+		$switched = true;
+	}
+
+	$terms = get_terms( $args );
+
+	if ( $switched ) {
+		restore_current_blog();
+	}
+
+	/**
+	 * Filter here to modify the BP Terms found into the database.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $terms The list of terms matching arguments.
+	 * @param array $args  Array of arguments used to query BP Terms.
+	 */
+	return apply_filters(
+		'bp_get_terms',
+		$terms,
+		$args
+	);
+}
+
+/**
+ * Deletes a BP Term.
+ *
+ * @since 7.0.0
+ *
+ * @param int     $term_id  The BP Term ID. Required.
+ * @param string  $taxonomy The BP Taxonomy Name. Required.
+ * @return bool|WP_Error True on success, WP_Error on failure.
+ */
+function bp_delete_term( $term_id = 0, $taxonomy = '' ) {
+	if ( ! $term_id || ! $taxonomy ) {
+		return new WP_Error( 'missing_arguments', __( 'Sorry, the term ID and the taxonomy are required arguments.', 'buddypress' ) );
+	}
+
+	$site_id = bp_get_taxonomy_term_site_id( $taxonomy );
+
+	$switched = false;
+	if ( $site_id !== get_current_blog_id() ) {
+		switch_to_blog( $site_id );
+		bp_register_taxonomies();
+		$switched = true;
+	}
+
+	/**
+	 * Fires before a BP Term is deleted from the database.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param int    $term_id  The BP Term ID.
+	 * @param string $taxonomy The BP Taxonomy Name.
+	 */
+	do_action( 'bp_before_delete_term', $term_id, $taxonomy );
+
+	$deleted = wp_delete_term( $term_id, $taxonomy );
+
+	if ( $switched ) {
+		restore_current_blog();
+	}
+
+	if ( is_wp_error( $deleted ) ) {
+		return $deleted;
+	}
+
+	if ( false === $deleted ) {
+		return new WP_Error( 'inexistant_term', __( 'Sorry, the term does not exist.', 'buddypress' ) );
+	}
+
+	if ( 0 === $deleted ) {
+		return new WP_Error( 'default_term', __( 'Sorry, the default term cannot be deleted.', 'buddypress' ) );
+	}
+
+	/**
+	 * Fires once a BP Term has been deleted from the database.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param boolean $deleted True.
+	 * @param int     $term_id  The deleted BP Term ID.
+	 * @param string  $taxonomy The BP Taxonomy Name of the deleted BP Term ID.
+	 */
+	do_action( 'bp_delete_term', $deleted, $term_id, $taxonomy );
+
+	return $deleted;
+}
diff --git src/bp-core/classes/class-bp-admin-types.php src/bp-core/classes/class-bp-admin-types.php
new file mode 100644
index 000000000..0ef4201ea
--- /dev/null
+++ src/bp-core/classes/class-bp-admin-types.php
@@ -0,0 +1,614 @@
+<?php
+/**
+ * BuddyPress Types Admin Class.
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ * @since 7.0.0
+ */
+
+// Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+if ( ! class_exists( 'BP_Admin_Types' ) ) :
+
+/**
+ * Load BuddyPress Types admin area.
+ *
+ * @since 7.O.0
+ */
+class BP_Admin_Types {
+	/**
+	 * Current BuddyPress taxonomy.
+	 *
+	 * @since 7.0.0
+	 * @var string
+	 */
+	public $taxonomy = '';
+
+	/**
+	 * All registered BuddyPress taxonomies.
+	 *
+	 * @since 7.0.0
+	 * @var array()
+	 */
+	public $taxonomies = array();
+
+	/**
+	 * Current screen ID.
+	 *
+	 * @since 7.0.0
+	 * @var string
+	 */
+	public $screen_id = '';
+
+	/**
+	 * The main BuddyPress Types admin loader.
+	 *
+	 * @since 7.0.0
+	 */
+	public function __construct() {
+		$this->setup_globals();
+
+		if ( $this->taxonomy && $this->screen_id ) {
+			$this->includes();
+			$this->setup_hooks();
+
+			if ( isset( $_POST['action'] ) || isset( $_GET['action'] ) ) {
+				if ( isset( $_GET['action'] ) ) {
+					$action = wp_unslash( $_GET['action'] );
+				} else {
+					$action = wp_unslash( $_POST['action'] );
+				}
+
+				$this->handle_action( $action );
+			}
+		}
+	}
+
+	/**
+	 * Register BP Types Admin.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @return BP_Admin_Types
+	 */
+	public static function register_types_admin() {
+		if ( ! is_admin() ) {
+			return;
+		}
+
+		$bp = buddypress();
+
+		if ( empty( $bp->core->types_admin ) ) {
+			$bp->core->types_admin = new self;
+		}
+
+		return $bp->core->types_admin;
+	}
+
+	/**
+	 * Set the globals.
+	 *
+	 * @since 7.0.0
+	 */
+	private function setup_globals() {
+		$current_screen = get_current_screen();
+
+		if ( isset( $current_screen->taxonomy ) && $current_screen->taxonomy ) {
+			$this->taxonomies = bp_get_default_taxonomies();
+
+			if ( isset( $this->taxonomies[ $current_screen->taxonomy ] ) ) {
+				$this->taxonomy  = $current_screen->taxonomy;
+				$this->screen_id = $current_screen->id;
+			}
+		}
+	}
+
+	/**
+	 * Include Admin functions.
+	 *
+	 * @since 7.0.0
+	 */
+	private function includes() {
+		require plugin_dir_path( dirname( __FILE__ ) ) . 'admin/bp-core-admin-types.php';
+	}
+
+	/**
+	 * Set hooks.
+	 *
+	 * @since 7.0.0
+	 */
+	private function setup_hooks() {
+		// Actions.
+		add_action( 'admin_head-edit-tags.php', array( $this, 'screen_head' ) );
+		add_action( 'admin_head-term.php', array( $this, 'screen_head' ) );
+		add_action( 'bp_admin_enqueue_scripts', array( $this, 'screen_scripts' ) );
+		add_action( "{$this->taxonomy}_add_form_fields", array( $this, 'add_form_fields' ), 10, 1 );
+		add_action( "{$this->taxonomy}_edit_form_fields", array( $this, 'edit_form_fields' ), 10, 2 );
+
+		// Filters
+		add_filter( 'bp_core_admin_register_scripts', array( $this, 'register_scripts' ) );
+		add_filter( "manage_{$this->screen_id}_columns", array( $this, 'column_headers' ), 10, 1 );
+		add_filter( "manage_{$this->taxonomy}_custom_column", array( $this, 'column_contents' ), 10, 3 );
+		add_filter( "{$this->taxonomy}_row_actions", array( $this, 'row_actions' ), 10, 2 );
+		add_filter( "bulk_actions-{$this->screen_id}", '__return_empty_array', 10, 1 );
+	}
+
+	/**
+	 * Handle BP Type actions.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param string $action Required. The action to handle ('add-tag', 'editedtag' or 'delete' ).
+	 */
+	private function handle_action( $action ) {
+		$referer = wp_get_referer();
+
+		// Adding a new type into the database.
+		if ( 'add-tag' === $action ) {
+			check_admin_referer( 'add-tag', '_wpnonce_add-tag' );
+
+			$result = bp_core_admin_insert_type( $_POST );
+
+			if ( is_wp_error( $result ) ) {
+				$referer = add_query_arg(
+					array_merge(
+						$result->get_error_data(),
+						array(
+							'error' => 1,
+						)
+					),
+					$referer
+				);
+
+				wp_safe_redirect( $referer );
+				exit;
+			}
+
+			wp_safe_redirect( add_query_arg( 'message', 2, $referer ) );
+			exit;
+
+			// Updating an existing type intot the Database.
+		} elseif ( 'editedtag' === $action ) {
+			$args                 = $_POST;
+			$args['type_term_id'] = 0;
+			unset( $args['tag_ID'] );
+
+			if ( isset( $_POST['tag_ID'] ) ) {
+				$args['type_term_id'] = $_POST['tag_ID'];
+			}
+
+			if ( isset( $_POST['taxonomy'] ) ) {
+				$args['taxonomy'] = $_POST['taxonomy'];
+			}
+
+			check_admin_referer( 'update-tag_' . $args['type_term_id'] );
+
+			$result = bp_core_admin_update_type( $args );
+
+			if ( is_wp_error( $result ) ) {
+				$referer = add_query_arg(
+					array_merge(
+						$result->get_error_data(),
+						array(
+							'error' => 1,
+						)
+					),
+					$referer
+				);
+
+				wp_safe_redirect( $referer );
+				exit;
+			}
+
+			wp_safe_redirect( add_query_arg( 'message', 4, $referer ) );
+			exit;
+
+			// Deletes a type.
+		} elseif ( 'delete' === $action ) {
+			$args                 = $_GET;
+			$args['type_term_id'] = 0;
+			unset( $args['tag_ID'] );
+
+			if ( isset( $_GET['tag_ID'] ) ) {
+				$args['type_term_id'] = $_GET['tag_ID'];
+			}
+
+			if ( isset( $_GET['taxonomy'] ) ) {
+				$args['taxonomy'] = $_GET['taxonomy'];
+			}
+
+			check_admin_referer( 'delete-tag_' . $args['type_term_id'] );
+			$referer = remove_query_arg( array( 'action', 'tag_ID', '_wpnonce' ), $referer );
+
+			// Delete the type.
+			$result = bp_core_admin_delete_type( $args );
+
+			if ( is_wp_error( $result ) ) {
+				$referer = add_query_arg(
+					array_merge(
+						$result->get_error_data(),
+						array(
+							'error' => 1,
+						)
+					),
+					$referer
+				);
+
+				wp_safe_redirect( $referer );
+				exit;
+			}
+
+			wp_safe_redirect( add_query_arg( 'message', 9, $referer ) );
+			exit;
+		}
+	}
+
+	/**
+	 * Override the Admin parent file to highlight the right menu.
+	 *
+	 * @since 7.0.0
+	 */
+	public function screen_head() {
+		global $parent_file;
+
+		if ( 'members' === $this->taxonomies[ $this->taxonomy ]['component'] ) {
+			$parent_file = 'users.php';
+		} else {
+			$parent_file = 'bp-' . $this->taxonomies[ $this->taxonomy ]['component'];
+		}
+	}
+
+	/**
+	 * Registers script.
+	 *
+	 * @since 7.0.0
+	 */
+	public function register_scripts( $scripts = array() ) {
+		// Neutralize WordPress Taxonomy scripts.
+		wp_dequeue_script( 'admin-tags' );
+		wp_dequeue_script( 'inline-edit-tax' );
+
+		// Adapt some styles.
+		wp_add_inline_style(
+			'common',
+			'.form-field:not(.bp-types-form), .term-bp_type_directory_slug-wrap:not(.bp-set-directory-slug), .edit-tag-actions #delete-link { display: none; }'
+		);
+
+		// Register the Types admin script.
+		return array_merge(
+			$scripts,
+			array(
+				'bp-admin-types' => array(
+					'file'         => sprintf(
+						'%1$sadmin/js/types-admin%2$s.js',
+						plugin_dir_url( dirname( __FILE__ ) ),
+						bp_core_get_minified_asset_suffix()
+					),
+					'dependencies' => array(),
+					'footer'       => true,
+				),
+			)
+		);
+	}
+
+	/**
+	 * Enqueues script.
+	 *
+	 * @since 7.0.0
+	 */
+	public function screen_scripts() {
+		wp_enqueue_script( 'bp-admin-types' );
+	}
+
+	/**
+	 * Outputs the BP type add form.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param string      $taxonomy The type taxonomy name.
+	 * @param null|object $type     The type object, `null` if not passed to the method.
+	 */
+	public function add_form_fields( $taxonomy = '', $type = null ) {
+		$taxonomy_object = get_taxonomy( $taxonomy );
+		$labels          = get_taxonomy_labels( $taxonomy_object );
+
+		// Default values for the Type ID field.
+		$type_id_label   = __( 'Type ID', 'buddypress' );
+		$type_id_desc    = __( 'Enter a lower-case string without spaces or special characters (used internally to identify the type).', 'buddypress' );
+
+		if ( isset( $labels->bp_type_id_label ) && $labels->bp_type_id_label ) {
+			$type_id_label = $labels->bp_type_id_label;
+		}
+
+		if ( isset( $labels->bp_type_id_description ) && $labels->bp_type_id_description ) {
+			$type_id_desc = $labels->bp_type_id_description;
+		}
+
+		// Outputs the Type ID field.
+		if ( isset( $type->name ) ) {
+			printf(
+				'<tr class="form-field bp-types-form form-required term-bp_type_id-wrap">
+					<th scope="row"><label for="bp_type_id">%1$s</label></th>
+					<td>
+						<input name="bp_type_id" id="bp_type_id" type="text" value="%2$s" size="40" disabled="disabled">
+					</td>
+				</tr>',
+				esc_html( $type_id_label ),
+				esc_attr( $type->name ),
+				esc_html( $type_id_desc )
+			);
+		} else {
+			printf(
+				'<div class="form-field bp-types-form form-required term-bp_type_id-wrap">
+					<label for="bp_type_id">%1$s</label>
+					<input name="bp_type_id" id="bp_type_id" type="text" value="" size="40" aria-required="true">
+					<p>%2$s</p>
+				</div>',
+				esc_html( $type_id_label ),
+				esc_html( $type_id_desc )
+			);
+		}
+
+		// Gets the Type's metadata.
+		$metafields = get_registered_meta_keys( 'term', $taxonomy );
+
+		foreach ( $metafields as $meta_key => $meta_schema ) {
+			if ( ! isset( $labels->{ $meta_key } ) || ! $labels->{ $meta_key } ) {
+				_doing_it_wrong(
+					__METHOD__,
+					__( 'Type metadata labels need to be set into the labels argument when registering your taxonomy using the meta key as the label’s key.', 'buddypress' )
+					. ' ' .
+					sprintf(
+						/* translators: %s is the name of the Type meta key */
+						__( 'As a result, the form elements for the "%s" meta key cannot be displayed', 'buddypress' ), $meta_key ),
+					'7.0.0'
+				);
+				continue;
+			}
+
+			$type_key = str_replace( 'bp_type_', '', $meta_key );
+
+			if ( 'string' === $meta_schema['type'] ) {
+				if ( isset( $type->name ) ) {
+					$type_prop_value = null;
+					if ( in_array( $type_key, array( 'name', 'singular_name' ), true ) ) {
+						if ( isset( $type->labels[ $type_key ] ) ) {
+							$type_prop_value = $type->labels[ $type_key ];
+						}
+
+					} elseif ( isset( $type->{$type_key} ) ) {
+						$type_prop_value = $type->{$type_key};
+					}
+
+					printf(
+						'<tr class="form-field bp-types-form form-required term-%1$s-wrap">
+							<th scope="row"><label for="%1$s">%2$s</label></th>
+							<td>
+								<input name="%1$s" id="%1$s" type="text" value="%3$s" size="40" aria-required="true">
+								<p class="description">%4$s</p>
+							</td>
+						</tr>',
+						esc_attr( $meta_key ),
+						esc_html( $labels->{ $meta_key } ),
+						esc_attr( $type_prop_value ),
+						esc_html( $meta_schema['description'] )
+					);
+
+				} else {
+					printf(
+						'<div class="form-field bp-types-form form-required term-%1$s-wrap">
+							<label for="%1$s">%2$s</label>
+							<input name="%1$s" id="%1$s" type="text" value="" size="40">
+							<p>%3$s</p>
+						</div>',
+						esc_attr( $meta_key ),
+						esc_html( $labels->{ $meta_key } ),
+						esc_html( $meta_schema['description'] )
+					);
+				}
+			} else {
+				if ( isset( $type->name ) ) {
+					$checked = '';
+					if ( isset( $type->{$type_key} ) && true === (bool) $type->{$type_key} ) {
+						$checked = ' checked="checked"';
+					}
+
+					printf(
+						'<tr class="form-field bp-types-form term-%1$s-wrap">
+							<th scope="row"><label for="%1$s">%2$s</label></th>
+							<td>
+								<input name="%1$s" id="%1$s" type="checkbox" value="1"%3$s> %4$s
+								<p class="description">%5$s</p>
+							</td>
+						</tr>',
+						esc_attr( $meta_key ),
+						esc_html( $labels->{ $meta_key } ),
+						$checked,
+						esc_html__( 'Yes', 'buddypress' ),
+						esc_html( $meta_schema['description'] )
+					);
+				} else {
+					printf(
+						'<div class="form-field bp-types-form term-%1$s-wrap">
+							<label for="%1$s">
+								<input name="%1$s" id="%1$s" type="checkbox" value="1"> %2$s
+							</label>
+							<p>%3$s</p>
+						</div>',
+						esc_attr( $meta_key ),
+						esc_html( $labels->{ $meta_key } ),
+						esc_html( $meta_schema['description'] )
+					);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Outputs the BP type edit form.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param WP_Term $term     The term object for the BP Type.
+	 * @param string  $taxonomy The type taxonomy name.
+	 * @return string           HTML Output.
+	 */
+	public function edit_form_fields( $term = null, $taxonomy = '' ) {
+		if ( ! isset( $term->name ) || ! $term->name || ! $taxonomy ) {
+			return;
+		}
+
+		$type         = new stdClass();
+		$type->name   = $term->name;
+		$type->labels = array();
+		$metadatas    = get_metadata( 'term', $term->term_id );
+
+		foreach ( $metadatas as $meta_key => $meta_values ) {
+			$meta_value = reset( $meta_values );
+			$type_key   = str_replace( 'bp_type_', '', $meta_key );
+
+			if ( in_array( $type_key, array( 'name', 'singular_name' ), true ) ) {
+				$type->labels[ $type_key ] = $meta_value;
+			} else {
+				$type->{$type_key} = $meta_value;
+			}
+		}
+
+		return $this->add_form_fields( $taxonomy, $type );
+	}
+
+	/**
+	 * Filters the terms list table column headers to customize them for BuddyPress Types.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array  $column_headers The column header labels keyed by column ID.
+	 * @return array                 The column header labels keyed by column ID.
+	 */
+	public function column_headers( $column_headers = array() ) {
+		if ( isset( $column_headers['name'] ) ) {
+			$column_headers['name'] = __( 'Type ID', 'buddypress' );
+		}
+
+		unset( $column_headers['cb'], $column_headers['description'], $column_headers['posts'] );
+
+		$column_headers['plural_name'] = __( 'Name', 'buddypress' );
+		$column_headers['counts']      = _x( 'Count', 'Number/count of types', 'buddypress' );
+
+		return $column_headers;
+	}
+
+	/**
+	 * Sets the content for the Plural name & Counts columns.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param string  $string      Blank string.
+	 * @param string  $column_name Name of the column.
+	 * @param int     $type_id     The type's term ID.
+	 * @return string              The Type Plural name.
+	 */
+	public function column_contents( $column_content = '', $column_name = '', $type_id = 0 ) {
+		if ( 'plural_name' !== $column_name && 'counts' !== $column_name || ! $type_id ) {
+			return $column_content;
+		}
+
+		// Set the Plural name column.
+		if ( 'plural_name' === $column_name ) {
+			$type_plural_name = get_term_meta( $type_id, 'bp_type_name', true );
+
+			// Plural name meta is not set? Let's check register by code types!
+			if ( ! $type_plural_name ) {
+				$type_name = get_term_field( 'name', $type_id, $this->taxonomy );
+
+				/**
+				 * Filter here to set missing term meta for registered by code types.
+				 *
+				 * @see bp_set_registered_by_code_member_type_metadata() for an example of use.
+				 *
+				 * @since 7.0.0
+				 *
+				 * @param string $value Metadata for the BP Type.
+				 */
+				$metadata = apply_filters( "{$this->taxonomy}_set_registered_by_code_metada", array(), $type_name );
+
+				if ( isset( $metadata['bp_type_name'] ) ) {
+					$type_plural_name = $metadata['bp_type_name'];
+				}
+			}
+
+			echo esc_html( $type_plural_name );
+
+			// Set the Totals column.
+		} elseif ( 'counts' === $column_name ) {
+			global $parent_file;
+			$type  = bp_get_term_by( 'id', $type_id, $this->taxonomy );
+			if ( 0 === (int) $type->count ) {
+				return 0;
+			}
+
+			// Format the count.
+			$count = number_format_i18n( $type->count );
+
+			$args = array(
+				str_replace( '_', '-', $this->taxonomy ) => $type->slug,
+			);
+
+			$base_url = $parent_file;
+			if ( false === strpos( $parent_file, '.php' ) ) {
+				$base_url = add_query_arg( 'page', $parent_file, 'admin.php' );
+			}
+
+			printf(
+				'<a href="%1$s">%2$s</a>',
+				esc_url( add_query_arg( $args, bp_get_admin_url( $base_url ) ) ),
+				esc_html( $count )
+			);
+		}
+	}
+
+	/**
+	 * Customizes the Types Admin list table row actions.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array   $actions The table row actions.
+	 * @param WP_Term $type    The current BP Type for the row.
+	 * @return array           The table row actions for the current BP type.
+	 */
+	public function row_actions( $actions = array(), $type = null ) {
+		if ( ! isset( $type->taxonomy ) || ! $type->taxonomy ) {
+			return $actions;
+		}
+
+		/**
+		 * Filter here to set the types "registered by code".
+		 *
+		 * @see bp_get_member_types_registered_by_code() for an example of use.
+		 *
+		 * @since 7.0.0
+		 */
+		$registered_by_code_types = apply_filters( "{$type->taxonomy}_registered_by_code", array() );
+
+		// Types registered by code cannot be deleted as long as the custom registration code exists.
+		if ( isset( $registered_by_code_types[ $type->name ] ) ) {
+			unset( $actions['delete'] );
+		}
+
+		// Inline edits are disabled for all types.
+		unset( $actions['inline hide-if-no-js'] );
+
+		// Removes the post type query argument for the edit action.
+		if ( isset( $actions['edit'] ) ) {
+			$actions['edit'] = str_replace( '&#038;post_type=post', '', $actions['edit'] );
+		}
+
+		return $actions;
+	}
+}
+
+endif;
diff --git src/bp-core/classes/class-bp-admin.php src/bp-core/classes/class-bp-admin.php
index 5457a816c..12487789e 100644
--- src/bp-core/classes/class-bp-admin.php
+++ src/bp-core/classes/class-bp-admin.php
@@ -175,6 +175,9 @@ class BP_Admin {
 		// BuddyPress Hello.
 		add_action( 'admin_footer', array( $this, 'about_screen' ) );
 
+		// BuddyPress Types administration.
+		add_action( 'load-edit-tags.php', array( 'BP_Admin_Types', 'register_types_admin' ) );
+
 		/* Filters ***********************************************************/
 
 		// Add link to settings page.
diff --git src/bp-groups/bp-groups-admin.php src/bp-groups/bp-groups-admin.php
index e41abf20a..8ddb55c3f 100644
--- src/bp-groups/bp-groups-admin.php
+++ src/bp-groups/bp-groups-admin.php
@@ -14,11 +14,14 @@
 defined( 'ABSPATH' ) || exit;
 
 // Include WP's list table class.
-if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
+if ( ! class_exists( 'WP_List_Table' ) ) {
+	require ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
+}
 
 // The per_page screen option. Has to be hooked in extremely early.
-if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-groups' == $_REQUEST['page'] )
+if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-groups' == $_REQUEST['page'] ) {
 	add_filter( 'set-screen-option', 'bp_groups_admin_screen_options', 10, 3 );
+}
 
 /**
  * Register the Groups component admin screen.
@@ -42,6 +45,58 @@ function bp_groups_add_admin_menu() {
 }
 add_action( bp_core_admin_hook(), 'bp_groups_add_admin_menu' );
 
+/**
+ * Redirects the user on the Goups network admin screen when BuddyPress is network activated.
+ *
+ * @since 1.1.0
+ */
+function bp_group_site_admin_network_admin_redirect() {
+	wp_safe_redirect( add_query_arg( 'page', 'bp-groups', network_admin_url( 'admin.php' ) ) );
+	exit();
+}
+
+function bp_groups_admin_types_menu() {
+	if ( ! bp_is_root_blog() ) {
+		return;
+	}
+
+	if ( bp_is_network_activated() && is_network_admin() ) {
+		// Adds a 'bp-groups' submenu to go to the root blog Group types screen.
+		$group_type_admin_url = add_query_arg( 'taxonomy', 'bp_group_type', get_admin_url( bp_get_root_blog_id(), 'edit-tags.php' ) );
+		add_submenu_page(
+			'bp-groups',
+			__( 'Group types', 'buddypress' ),
+			__( 'Group types', 'buddypress' ),
+			'bp_moderate',
+			esc_url( $group_type_admin_url )
+		);
+	} elseif ( ! is_network_admin() ) {
+		if ( is_multisite() ) {
+			// Adds a 'bp-groups' menu to the root blog menu.
+			$redirect_hook = add_menu_page(
+				_x( 'Groups', 'Admin Groups page title', 'buddypress' ),
+				_x( 'Groups', 'Admin Groups menu', 'buddypress' ),
+				'bp_moderate',
+				'bp-groups',
+				'__return_empty_string',
+				'div'
+			);
+
+			add_action( "load-{$redirect_hook}", 'bp_group_site_admin_network_admin_redirect' );
+		}
+
+		// Add the submenu to manage Group Types.
+		add_submenu_page(
+			'bp-groups',
+			__( 'Group types', 'buddypress' ),
+			__( 'Group types', 'buddypress' ),
+			'bp_moderate',
+			basename( add_query_arg( 'taxonomy', 'bp_group_type', bp_get_admin_url( 'edit-tags.php' ) ) )
+		);
+	}
+}
+add_action( 'bp_admin_menu', 'bp_groups_admin_types_menu' );
+
 /**
  * Add groups component to custom menus array.
  *
@@ -1408,3 +1463,51 @@ function bp_groups_admin_groups_type_change_notice() {
 	}
 }
 add_action( bp_core_admin_hook(), 'bp_groups_admin_groups_type_change_notice' );
+
+/**
+ * Checks whether a group type already exists.
+ *
+ * @since 7.0.0
+ *
+ * @param  boolean $exists  True if the group type already exists. False otherwise.
+ * @param  string  $type_id The group type identifier.
+ * @return boolean          True if the group type already exists. False otherwise.
+ */
+function bp_groups_type_admin_type_exists( $exists = false, $type_id = '' ) {
+	if ( ! $type_id ) {
+		return $exists;
+	}
+
+	return ! is_null( bp_groups_get_group_type_object( $type_id ) );
+}
+add_filter( bp_get_group_type_tax_name() . '_check_existing_type', 'bp_groups_type_admin_type_exists', 1, 2 );
+
+/**
+ * Set the feedback messages for the Group Types Admin actions.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $messages The feedback messages.
+ * @return array           The feedback messages including the ones for the Group Types Admin actions.
+ */
+function bp_groups_type_admin_updated_messages( $messages = array() ) {
+	$type_taxonomy = bp_get_group_type_tax_name();
+
+	$messages[ $type_taxonomy ] = array(
+		0  => '',
+		1  => __( 'Please define the Group Type ID field.', 'buddypress' ),
+		2  => __( 'Group type successfully added.', 'buddypress' ),
+		3  => __( 'Sorry, there was an error and the Group type wasn’t added.', 'buddypress' ),
+		// The following one needs to be != 5.
+		4  => __( 'Group type successfully updated.', 'buddypress' ),
+		5  => __( 'Sorry, this Group type already exists.', 'buddypress' ),
+		6  => __( 'Sorry, the Group type was not deleted: it does not exist.', 'buddypress' ),
+		7  => __( 'Sorry, This Group type is registered using code, deactivate the plugin or remove the custom code before trying to delete it again.', 'buddypress' ),
+		8  => __( 'Sorry, there was an error while trying to delete this Group type.', 'buddypress' ),
+		9  => __( 'Group type successfully deleted.', 'buddypress' ),
+		10 => __( 'Group type could not be updated due to missing required information.', 'buddypress' ),
+	);
+
+	return $messages;
+}
+add_filter( 'term_updated_messages', 'bp_groups_type_admin_updated_messages' );
diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php
index f1bd15f35..389059f88 100644
--- src/bp-groups/bp-groups-functions.php
+++ src/bp-groups/bp-groups-functions.php
@@ -2463,6 +2463,130 @@ add_action( 'bp_groups_delete_group', 'bp_groups_update_orphaned_groups_on_group
 
 /** Group Types ***************************************************************/
 
+/**
+ * Output the slug of the Group type taxonomy.
+ *
+ * @since 7.0.0
+ */
+function bp_group_type_tax_name() {
+	echo bp_get_group_type_tax_name();
+}
+
+	/**
+	 * Return the slug of the Group type taxonomy.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @return string The unique Group taxonomy slug.
+	 */
+	function bp_get_group_type_tax_name() {
+		/**
+		 * Filters the slug of the Group type taxonomy.
+		 *
+		 * @since 7.0.0
+		 *
+		 * @param string $value Group type taxonomy slug.
+		 */
+		return apply_filters( 'bp_get_group_type_tax_name', 'bp_group_type' );
+	}
+
+/**
+ * Returns labels used by the Group type taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @return array
+ */
+function bp_get_group_type_tax_labels() {
+
+	/**
+	 * Filters Group type taxonomy labels.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $value Associative array (name => label).
+	 */
+	return apply_filters(
+		'bp_get_group_type_tax_labels',
+		array(
+			'name'                          => _x( 'Group types', 'Group type taxonomy name', 'buddypress' ),
+			'singular_name'                 => _x( 'Group type', 'Group type taxonomy singular name', 'buddypress' ),
+			'search_items'                  => _x( 'Search Group types', 'Group type taxonomy search items label', 'buddypress' ),
+			'popular_items'                 => _x( 'Most used Group types', 'Group type taxonomy popular items label', 'buddypress' ),
+			'all_items'                     => _x( 'All Group types', 'Group type taxonomy all items label', 'buddypress' ),
+			'edit_item'                     => _x( 'Edit Group type', 'Group type taxonomy edit item label', 'buddypress' ),
+			'view_item'                     => _x( 'View Group type', 'Group type taxonomy view item label', 'buddypress' ),
+			'update_item'                   => _x( 'Update Group type', 'Group type taxonomy update item label', 'buddypress' ),
+			'add_new_item'                  => _x( 'Add new Group type', 'Group type taxonomy add new item label', 'buddypress' ),
+			'new_item_name'                 => _x( 'New Group type name', 'Group type taxonomy new item name label', 'buddypress' ),
+			'separate_items_with_commas'    => _x( 'Separate Group types with commas', 'Group type taxonomy separate items with commas label', 'buddypress' ),
+			'add_or_remove_items'           => _x( 'Add or remove Group types', 'Group type taxonomy add or remove items label', 'buddypress' ),
+			'choose_from_most_used'         => _x( 'Choose from the most used Group types', 'Group type taxonomy choose from most used label', 'buddypress' ),
+			'not_found'                     => _x( 'No Group types found', 'Group type taxonomy not found label', 'buddypress' ),
+			'no_terms'                      => _x( 'No Group types', 'Group type taxonomy no terms label', 'buddypress' ),
+			'items_list_navigation'         => _x( 'Group types list navigation', 'Group type taxonomy items list navigation label', 'buddypress' ),
+			'items_list'                    => _x( 'Group types list', 'Group type taxonomy items list label', 'buddypress' ),
+			'back_to_items'                 => _x( 'Back to all Group types', 'Group type taxonomy back to items label', 'buddypress' ),
+			// Specific to BuddyPress.
+			'bp_type_id_label'              => _x( 'Group Type ID', 'BP Member type ID label', 'buddypress' ),
+			'bp_type_id_description'        => _x( 'Enter a lower-case string without spaces or special characters (used internally to identify the group type).', 'BP Group type ID description', 'buddypress' ),
+			'bp_type_show_in_create_screen' => _x( 'Add to Available Types on Create Screen', 'BP Group type show in create screen', 'buddypress' ),
+			'bp_type_show_in_list'          => _x( 'Include when Group Types are Listed for a Group', 'BP Group type show in list', 'buddypress' ),
+		)
+	);
+}
+
+/**
+ * Returns arguments used by the Group type taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @return array
+ */
+function bp_get_group_type_tax_args() {
+
+	/**
+	 * Filters Group type taxonomy args.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $value Associative array (key => arg).
+	 */
+	return apply_filters(
+		'bp_get_group_type_tax_args',
+		array_merge(
+			array(
+				'description' => _x( 'BuddyPress Group types', 'Group type taxonomy description', 'buddypress' ),
+				'labels'      => array_merge( bp_get_group_type_tax_labels(), bp_get_taxonomy_common_labels() ),
+			),
+			bp_get_taxonomy_common_args()
+		)
+	);
+}
+
+/**
+ * Register the Group Types taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @param array $taxonomies BuddyPress default taxonomies.
+ * @return array            BuddyPress default taxonomies.
+ */
+function bp_groups_register_group_type_taxonomy( $taxonomies = array() ) {
+	return array_merge(
+		$taxonomies,
+		array(
+			// Group Type.
+			bp_get_group_type_tax_name() => array(
+				'object'    => 'bp_group',
+				'component' => 'groups',
+				'args'      => bp_get_group_type_tax_args(),
+			),
+		)
+	);
+}
+add_filter( 'bp_get_default_taxonomies', 'bp_groups_register_group_type_taxonomy', 1 );
+
 /**
  * Fire the 'bp_groups_register_group_types' action.
  *
@@ -2478,6 +2602,62 @@ function bp_groups_register_group_types() {
 }
 add_action( 'bp_register_taxonomies', 'bp_groups_register_group_types' );
 
+/**
+ * Extend generic Type metadata schema to match Group Type needs.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $schema   The generic Type metadata schema.
+ * @param string $taxonomy The taxonomy name the schema applies to.
+ * @return array           The Group Type metadata schema.
+ */
+function bp_get_group_type_metadata_schema( $schema = array(), $taxonomy = '' ) {
+	if ( bp_get_group_type_tax_name() === $taxonomy ) {
+		if ( isset( $schema['bp_type_has_directory']['description'] ) ) {
+			$schema['bp_type_has_directory']['description'] = __( 'Add a list of groups matching the member type available on the Groups Directory page (e.g. site.url/groups/type/ninja/).', 'buddypress' );
+		}
+
+		if ( isset( $schema['bp_type_directory_slug']['description'] ) ) {
+			$schema['bp_type_directory_slug']['description'] = __( 'If you want to use a slug that is different from the Group Type ID above, enter it here.', 'buddypress' );
+		}
+
+		$schema = array_merge(
+			$schema,
+			array(
+				'bp_type_show_in_create_screen' => array(
+					'description'       => __( 'Include this group type during group creation and when a group administrator is on the group&rsquo;s &ldquo;Manage > Settings&rdquo; page.', 'buddypress' ),
+					'type'              => 'boolean',
+					'single'            => true,
+					'sanitize_callback' => 'absint',
+				),
+				'bp_type_show_in_list'          => array(
+					'description'       => __( 'Include this group type when group types are listed, like in the group header.', 'buddypress' ),
+					'type'              => 'boolean',
+					'single'            => true,
+					'sanitize_callback' => 'absint',
+				),
+			)
+		);
+	}
+
+	return $schema;
+}
+add_filter( 'bp_get_type_metadata_schema', 'bp_get_group_type_metadata_schema', 1, 2 );
+
+/**
+ * Registers the Group type metadata.
+ *
+ * @since 7.0.0
+ */
+function bp_register_group_type_metadata() {
+	$type_taxonomy = bp_get_group_type_tax_name();
+
+	foreach ( bp_get_type_metadata_schema( false, $type_taxonomy ) as $meta_key => $meta_args ) {
+		bp_register_type_meta( $type_taxonomy, $meta_key, $meta_args );
+	}
+}
+add_action( 'bp_register_type_metadata', 'bp_register_group_type_metadata', 11 );
+
 /**
  * Register a group type.
  *
@@ -2525,6 +2705,8 @@ function bp_groups_register_group_type( $group_type, $args = array() ) {
 		'description'           => '',
 		'create_screen_checked' => false,
 		'labels'                => array(),
+		'code'                  => true,
+		'db_id'                 => 0,
 	), 'register_group_type' );
 
 	$group_type = sanitize_key( $group_type );
@@ -2617,6 +2799,11 @@ function bp_groups_get_group_types( $args = array(), $output = 'names', $operato
 
 	$types = wp_filter_object_list( $types, $args, $operator );
 
+	// Merge with types available into the database.
+	if ( ! isset( $args['code'] ) || true !== $args['code'] ) {
+		$types = bp_get_taxonomy_types( bp_get_group_type_tax_name(), $types );
+	}
+
 	/**
 	 * Filters the array of group type objects.
 	 *
@@ -2656,6 +2843,78 @@ function bp_groups_get_group_type_object( $group_type ) {
 	return $types[ $group_type ];
 }
 
+/**
+ * Only gets the group types registered by code.
+ *
+ * @since 7.0.0
+ *
+ * @return array The group types registered by code.
+ */
+function bp_get_group_types_registered_by_code() {
+	return bp_groups_get_group_types(
+		array(
+			'code' => true,
+		),
+		'objects'
+	);
+}
+add_filter( bp_get_group_type_tax_name() . '_registered_by_code', 'bp_get_group_types_registered_by_code' );
+
+/**
+ * Generates missing metadata for a type registered by code.
+ *
+ * @since 7.0.0
+ *
+ * @return array The group type metadata.
+ */
+function bp_set_registered_by_code_group_type_metadata( $metadata = array(), $type = '' ) {
+	$group_type = bp_groups_get_group_type_object( $type );
+
+	foreach ( get_object_vars( $group_type ) as $object_key => $object_value ) {
+		if ( 'labels' === $object_key ) {
+			foreach ( $object_value as $label_key => $label_value ) {
+				$metadata[ 'bp_type_' . $label_key ] = $label_value;
+			}
+		} elseif ( ! in_array( $object_key, array( 'name', 'code', 'db_id' ), true ) ) {
+			$metadata[ 'bp_type_' . $object_key ] = $object_value;
+		}
+	}
+
+	/**
+	 * Save metadata into database to avoid generating metadata
+	 * each time a type is listed into the Types Admin screen.
+	 */
+	if ( isset( $group_type->db_id ) && $group_type->db_id ) {
+		bp_update_type_metadata( $group_type->db_id, bp_get_group_type_tax_name(), $metadata );
+	}
+
+	return $metadata;
+}
+add_filter( bp_get_group_type_tax_name() . '_set_registered_by_code_metada', 'bp_set_registered_by_code_group_type_metadata', 10, 2 );
+
+/**
+ * Insert group types registered by code not yet saved into the database as WP Terms.
+ *
+ * @since 7.0.0
+ */
+function bp_insert_group_types_registered_by_code() {
+	$all_types     = bp_groups_get_group_types( array(), 'objects' );
+	$unsaved_types = wp_filter_object_list( $all_types, array( 'db_id' => 0 ), 'and', 'name' );
+
+	if ( $unsaved_types ) {
+		foreach ( $unsaved_types as $type_name ) {
+			bp_insert_term(
+				$type_name,
+				bp_get_group_type_tax_name(),
+				array(
+					'slug' => $type_name,
+				)
+			);
+		}
+	}
+}
+add_action( bp_get_group_type_tax_name() . '_add_form', 'bp_insert_group_types_registered_by_code', 1 );
+
 /**
  * Set type for a group.
  *
@@ -2685,7 +2944,7 @@ function bp_groups_set_group_type( $group_id, $group_type, $append = false ) {
 		}
 	}
 
-	$retval = bp_set_object_terms( $group_id, $group_type, 'bp_group_type', $append );
+	$retval = bp_set_object_terms( $group_id, $group_type, bp_get_group_type_tax_name(), $append );
 
 	// Bust the cache if the type has been updated.
 	if ( ! is_wp_error( $retval ) ) {
@@ -2721,7 +2980,7 @@ function bp_groups_get_group_type( $group_id, $single = true ) {
 	$types = wp_cache_get( $group_id, 'bp_groups_group_type' );
 
 	if ( false === $types ) {
-		$raw_types = bp_get_object_terms( $group_id, 'bp_group_type' );
+		$raw_types = bp_get_object_terms( $group_id, bp_get_group_type_tax_name() );
 
 		if ( ! is_wp_error( $raw_types ) ) {
 			$types = array();
@@ -2778,7 +3037,7 @@ function bp_groups_remove_group_type( $group_id, $group_type ) {
 		return false;
 	}
 
-	$deleted = bp_remove_object_terms( $group_id, $group_type, 'bp_group_type' );
+	$deleted = bp_remove_object_terms( $group_id, $group_type, bp_get_group_type_tax_name() );
 
 	// Bust the case, if the type has been removed.
 	if ( ! is_wp_error( $deleted ) ) {
diff --git src/bp-groups/classes/class-bp-groups-component.php src/bp-groups/classes/class-bp-groups-component.php
index a7c2f5c5c..d78176442 100644
--- src/bp-groups/classes/class-bp-groups-component.php
+++ src/bp-groups/classes/class-bp-groups-component.php
@@ -924,12 +924,18 @@ class BP_Groups_Component extends BP_Component {
 	 * Set up taxonomies.
 	 *
 	 * @since 2.6.0
+	 * @deprecated 7.0.0
 	 */
 	public function register_taxonomies() {
-		// Group Type.
-		register_taxonomy( 'bp_group_type', 'bp_group', array(
-			'public' => false,
-		) );
+		/**
+		 * Since 7.0.0 The Group Type taxonomy is registered using the
+		 * `bp_groups_register_group_type_taxonomy()` function.
+		 *
+		 * @see bp-groups/bp-groups-functions.php.
+		 */
+
+		// Just let BP Component fire 'bp_groups_register_taxonomies'.
+		return parent::register_taxonomies();
 	}
 
 	/**
diff --git src/bp-groups/classes/class-bp-groups-group.php src/bp-groups/classes/class-bp-groups-group.php
index 0102e41e7..f06ec8055 100644
--- src/bp-groups/classes/class-bp-groups-group.php
+++ src/bp-groups/classes/class-bp-groups-group.php
@@ -1746,14 +1746,14 @@ class BP_Groups_Group {
 
 		$tax_query = new WP_Tax_Query( array(
 			array(
-				'taxonomy' => 'bp_group_type',
+				'taxonomy' => bp_get_group_type_tax_name(),
 				'field'    => 'name',
 				'operator' => $operator,
 				'terms'    => $types,
 			),
 		) );
 
-		$site_id  = bp_get_taxonomy_term_site_id( 'bp_group_type' );
+		$site_id  = bp_get_taxonomy_term_site_id( bp_get_group_type_tax_name() );
 		$switched = false;
 		if ( $site_id !== get_current_blog_id() ) {
 			switch_to_blog( $site_id );
diff --git src/bp-members/bp-members-admin.php src/bp-members/bp-members-admin.php
index 1d3b875f0..3f852ca31 100644
--- src/bp-members/bp-members-admin.php
+++ src/bp-members/bp-members-admin.php
@@ -12,3 +12,85 @@ defined( 'ABSPATH' ) || exit;
 
 // Load the BP Members admin.
 add_action( 'bp_init', array( 'BP_Members_Admin', 'register_members_admin' ) );
+
+/**
+ * Create Users submenu to manage BuddyPress types.
+ *
+ * @since 7.0.0
+ */
+function bp_members_type_admin_menu() {
+	if ( ! bp_is_root_blog() ) {
+		return;
+	}
+
+	if ( bp_is_network_activated() && is_network_admin() ) {
+		// Adds a users.php submenu to go to the root blog Member types screen.
+		$member_type_admin_url = add_query_arg( 'taxonomy', bp_get_member_type_tax_name(), get_admin_url( bp_get_root_blog_id(), 'edit-tags.php' ) );
+
+		add_submenu_page(
+			'users.php',
+			__( 'Member types', 'buddypress' ),
+			__( 'Member types', 'buddypress' ),
+			'bp_moderate',
+			esc_url( $member_type_admin_url )
+		);
+
+	} elseif ( ! is_network_admin() ) {
+		add_submenu_page(
+			'users.php',
+			__( 'Member types', 'buddypress' ),
+			__( 'Member types', 'buddypress' ),
+			'bp_moderate',
+			basename( add_query_arg( 'taxonomy', bp_get_member_type_tax_name(), bp_get_admin_url( 'edit-tags.php' ) ) )
+		);
+	}
+}
+add_action( 'bp_admin_menu', 'bp_members_type_admin_menu' );
+
+/**
+ * Checks whether a member type already exists.
+ *
+ * @since 7.0.0
+ *
+ * @param  boolean $exists  True if the member type already exists. False otherwise.
+ * @param  string  $type_id The member type identifier.
+ * @return boolean          True if the member type already exists. False otherwise.
+ */
+function bp_members_type_admin_type_exists( $exists = false, $type_id = '' ) {
+	if ( ! $type_id ) {
+		return $exists;
+	}
+
+	return ! is_null( bp_get_member_type_object( $type_id ) );
+}
+add_filter( bp_get_member_type_tax_name() . '_check_existing_type', 'bp_members_type_admin_type_exists', 1, 2 );
+
+/**
+ * Set the feedback messages for the Member Types Admin actions.
+ *
+ * @since 7.0.0
+ *
+ * @param array  $messages The feedback messages.
+ * @return array           The feedback messages including the ones for the Member Types Admin actions.
+ */
+function bp_members_type_admin_updated_messages( $messages = array() ) {
+	$type_taxonomy = bp_get_member_type_tax_name();
+
+	$messages[ $type_taxonomy ] = array(
+		0  => '',
+		1  => __( 'Please define the Member Type ID field.', 'buddypress' ),
+		2  => __( 'Member type successfully added.', 'buddypress' ),
+		3  => __( 'Sorry, there was an error and the Member type wasn’t added.', 'buddypress' ),
+		// The following one needs to be != 5.
+		4  => __( 'Member type successfully updated.', 'buddypress' ),
+		5  => __( 'Sorry, this Member type already exists.', 'buddypress' ),
+		6  => __( 'Sorry, the Member type was not deleted: it does not exist.', 'buddypress' ),
+		7  => __( 'Sorry, This Member type is registered using code, deactivate the plugin or remove the custom code before trying to delete it again.', 'buddypress' ),
+		8  => __( 'Sorry, there was an error while trying to delete this Member type.', 'buddypress' ),
+		9  => __( 'Member type successfully deleted.', 'buddypress' ),
+		10 => __( 'Member type could not be updated due to missing required information.', 'buddypress' ),
+	);
+
+	return $messages;
+}
+add_filter( 'term_updated_messages', 'bp_members_type_admin_updated_messages' );
diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php
index 925759030..411250c59 100644
--- src/bp-members/bp-members-functions.php
+++ src/bp-members/bp-members-functions.php
@@ -2645,6 +2645,92 @@ function bp_member_type_tax_name() {
 		return apply_filters( 'bp_get_member_type_tax_name', 'bp_member_type' );
 	}
 
+/**
+ * Returns labels used by the member type taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @return array
+ */
+function bp_get_member_type_tax_labels() {
+
+	/**
+	 * Filters Member type taxonomy labels.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $value Associative array (name => label).
+	 */
+	return apply_filters(
+		'bp_get_member_type_tax_labels',
+		array(
+			'name'                       => _x( 'Member types', 'Member type taxonomy name', 'buddypress' ),
+			'singular_name'              => _x( 'Member type', 'Member type taxonomy singular name', 'buddypress' ),
+			'search_items'               => _x( 'Search Member types', 'Member type taxonomy search items label', 'buddypress' ),
+			'popular_items'              => _x( 'Most used Member types', 'Member type taxonomy popular items label', 'buddypress' ),
+			'all_items'                  => _x( 'All Member types', 'Member type taxonomy all items label', 'buddypress' ),
+			'edit_item'                  => _x( 'Edit Member type', 'Member type taxonomy edit item label', 'buddypress' ),
+			'view_item'                  => _x( 'View Member type', 'Member type taxonomy view item label', 'buddypress' ),
+			'update_item'                => _x( 'Update Member type', 'Member type taxonomy update item label', 'buddypress' ),
+			'add_new_item'               => _x( 'Add new Member type', 'Member type taxonomy add new item label', 'buddypress' ),
+			'new_item_name'              => _x( 'New Member type name', 'Member type taxonomy new item name label', 'buddypress' ),
+			'separate_items_with_commas' => _x( 'Separate Member types with commas', 'Member type taxonomy separate items with commas label', 'buddypress' ),
+			'add_or_remove_items'        => _x( 'Add or remove Member types', 'Member type taxonomy add or remove items label', 'buddypress' ),
+			'choose_from_most_used'      => _x( 'Choose from the most used Member types', 'Member type taxonomy choose from most used label', 'buddypress' ),
+			'not_found'                  => _x( 'No Member types found', 'Member type taxonomy not found label', 'buddypress' ),
+			'no_terms'                   => _x( 'No Member types', 'Member type taxonomy no terms label', 'buddypress' ),
+			'items_list_navigation'      => _x( 'Member types list navigation', 'Member type taxonomy items list navigation label', 'buddypress' ),
+			'items_list'                 => _x( 'Member types list', 'Member type taxonomy items list label', 'buddypress' ),
+			'back_to_items'              => _x( 'Back to all Member types', 'Member type taxonomy back to items label', 'buddypress' ),
+			// Specific to BuddyPress.
+			'bp_type_id_label'           => _x( 'Member Type ID', 'BP Member type ID label', 'buddypress' ),
+			'bp_type_id_description'     => _x( 'Enter a lower-case string without spaces or special characters (used internally to identify the member type).', 'BP Member type ID description', 'buddypress' ),
+		)
+	);
+}
+
+/**
+ * Returns arguments used by the Member type taxonomy.
+ *
+ * @since 7.0.0
+ *
+ * @return array
+ */
+function bp_get_member_type_tax_args() {
+
+	/**
+	 * Filters Member type taxonomy args.
+	 *
+	 * @since 7.0.0
+	 *
+	 * @param array $value Associative array (key => arg).
+	 */
+	return apply_filters(
+		'bp_get_member_type_tax_args',
+		array_merge(
+			array(
+				'description' => _x( 'BuddyPress Member types', 'Member type taxonomy description', 'buddypress' ),
+				'labels'      => array_merge( bp_get_member_type_tax_labels(), bp_get_taxonomy_common_labels() ),
+			),
+			bp_get_taxonomy_common_args()
+		)
+	);
+}
+
+/**
+ * Registers the Member type metadata.
+ *
+ * @since 7.0.0
+ */
+function bp_register_member_type_metadata() {
+	$type_taxonomy = bp_get_member_type_tax_name();
+
+	foreach ( bp_get_type_metadata_schema( false, $type_taxonomy ) as $meta_key => $meta_args ) {
+		bp_register_type_meta( $type_taxonomy, $meta_key, $meta_args );
+	}
+}
+add_action( 'bp_register_type_metadata', 'bp_register_member_type_metadata' );
+
 /**
  * Register a member type.
  *
@@ -2677,6 +2763,8 @@ function bp_register_member_type( $member_type, $args = array() ) {
 	$r = bp_parse_args( $args, array(
 		'labels'        => array(),
 		'has_directory' => true,
+		'code'          => true,
+		'db_id'         => 0,
 	), 'register_member_type' );
 
 	$member_type = sanitize_key( $member_type );
@@ -2776,6 +2864,11 @@ function bp_get_member_type_object( $member_type ) {
 function bp_get_member_types( $args = array(), $output = 'names', $operator = 'and' ) {
 	$types = buddypress()->members->types;
 
+	// Merge with types available into the database.
+	if ( ! isset( $args['code'] ) || true !== $args['code'] ) {
+		$types = bp_get_taxonomy_types( bp_get_member_type_tax_name(), $types );
+	}
+
 	$types = wp_filter_object_list( $types, $args, $operator );
 
 	/**
@@ -2799,6 +2892,78 @@ function bp_get_member_types( $args = array(), $output = 'names', $operator = 'a
 	return $types;
 }
 
+/**
+ * Only gets the member types registered by code.
+ *
+ * @since 7.0.0
+ *
+ * @return array The member types registered by code.
+ */
+function bp_get_member_types_registered_by_code() {
+	return bp_get_member_types(
+		array(
+			'code' => true,
+		),
+		'objects'
+	);
+}
+add_filter( bp_get_member_type_tax_name() . '_registered_by_code', 'bp_get_member_types_registered_by_code' );
+
+/**
+ * Generates missing metadata for a type registered by code.
+ *
+ * @since 7.0.0
+ *
+ * @return array The member type metadata.
+ */
+function bp_set_registered_by_code_member_type_metadata( $metadata = array(), $type = '' ) {
+	$member_type = bp_get_member_type_object( $type );
+
+	foreach ( get_object_vars( $member_type ) as $object_key => $object_value ) {
+		if ( 'labels' === $object_key ) {
+			foreach ( $object_value as $label_key => $label_value ) {
+				$metadata[ 'bp_type_' . $label_key ] = $label_value;
+			}
+		} elseif ( ! in_array( $object_key, array( 'name', 'code', 'db_id' ), true ) ) {
+			$metadata[ 'bp_type_' . $object_key ] = $object_value;
+		}
+	}
+
+	/**
+	 * Save metadata into database to avoid generating metadata
+	 * each time a type is listed into the Types Admin screen.
+	 */
+	if ( isset( $member_type->db_id ) && $member_type->db_id ) {
+		bp_update_type_metadata( $member_type->db_id, bp_get_member_type_tax_name(), $metadata );
+	}
+
+	return $metadata;
+}
+add_filter( bp_get_member_type_tax_name() . '_set_registered_by_code_metada', 'bp_set_registered_by_code_member_type_metadata', 10, 2 );
+
+/**
+ * Insert member types registered by code not yet saved into the database as WP Terms.
+ *
+ * @since 7.0.0
+ */
+function bp_insert_member_types_registered_by_code() {
+	$all_types     = bp_get_member_types( array(), 'objects' );
+	$unsaved_types = wp_filter_object_list( $all_types, array( 'db_id' => 0 ), 'and', 'name' );
+
+	if ( $unsaved_types ) {
+		foreach ( $unsaved_types as $type_name ) {
+			bp_insert_term(
+				$type_name,
+				bp_get_member_type_tax_name(),
+				array(
+					'slug' => $type_name,
+				)
+			);
+		}
+	}
+}
+add_action( bp_get_member_type_tax_name() . '_add_form', 'bp_insert_member_types_registered_by_code', 1 );
+
 /**
  * Set type for a member.
  *
diff --git src/class-buddypress.php src/class-buddypress.php
index 5464e5c4a..e3aab8198 100644
--- src/class-buddypress.php
+++ src/class-buddypress.php
@@ -592,6 +592,7 @@ class BuddyPress {
 			'BP_Invitation'                => 'core',
 			'BP_REST_Components_Endpoint'  => 'core',
 			'BP_REST_Attachments'          => 'core',
+			'BP_Admin_Types'               => 'core',
 
 			'BP_Core_Friends_Widget'   => 'friends',
 			'BP_REST_Friends_Endpoint' => 'friends',
