diff --git src/bp-core/admin/bp-core-admin-schema.php src/bp-core/admin/bp-core-admin-schema.php
index 6f9043a..44506bf 100644
--- src/bp-core/admin/bp-core-admin-schema.php
+++ src/bp-core/admin/bp-core-admin-schema.php
@@ -202,10 +202,12 @@ function bp_core_install_groups() {
 				slug varchar(200) NOT NULL,
 				description longtext NOT NULL,
 				status varchar(10) NOT NULL DEFAULT 'public',
+				parent_id bigint(20) NOT NULL DEFAULT 0,
 				enable_forum tinyint(1) NOT NULL DEFAULT '1',
 				date_created datetime NOT NULL,
 				KEY creator_id (creator_id),
-				KEY status (status)
+				KEY status (status),
+				KEY parent_id (parent_id)
 			) {$charset_collate};";
 
 	$sql[] = "CREATE TABLE {$bp_prefix}bp_groups_members (
diff --git src/bp-core/bp-core-update.php src/bp-core/bp-core-update.php
index 16608a4..c16a324 100644
--- src/bp-core/bp-core-update.php
+++ src/bp-core/bp-core-update.php
@@ -508,11 +508,20 @@ function bp_update_to_2_5() {
  * 2.7.0 update routine.
  *
  * - Add email unsubscribe salt.
+ * - Add `parent_id` column to groups table.
  *
  * @since 2.7.0
  */
 function bp_update_to_2_7() {
 	bp_add_option( 'bp-emails-unsubscribe-salt', base64_encode( wp_generate_password( 64, true, true ) ) );
+
+	/*
+	 * Also handled by `bp_core_install()`.
+	 * Add `parent_id` column to groups table.
+	 */
+	if ( bp_is_active( 'groups' ) ) {
+		bp_core_install_groups();
+	}
 }
 
 /**
diff --git src/bp-groups/bp-groups-actions.php src/bp-groups/bp-groups-actions.php
index 4a3c510..faf065d 100644
--- src/bp-groups/bp-groups-actions.php
+++ src/bp-groups/bp-groups-actions.php
@@ -566,3 +566,32 @@ function groups_action_group_feed() {
 	) );
 }
 add_action( 'bp_actions', 'groups_action_group_feed' );
+
+/**
+ * Update orphaned child groups when the parent is deleted.
+ *
+ * @since 2.7.0
+ *
+ * @param BP_Groups_Group $group Instance of the group item being deleted.
+ */
+function bp_groups_update_orphaned_groups_on_group_delete( $group ) {
+	// Get child groups and set the parent to the deleted parent's parent.
+	$grandparent_group_id = ! empty( $group->parent_id ) ? $group->parent_id : 0;
+	$child_args = array(
+		'parent_id'         => $group->id,
+		'show_hidden'       => true,
+		'per_page'          => false,
+		'populate_extras'   => false,
+		'update_meta_cache' => false,
+	);
+	$children = groups_get_groups( $child_args );
+	$children = $children['groups'];
+
+	foreach ( $children as $cgroup ) {
+		// Create the BP_Groups_Group object.
+		$child_group = groups_get_group( array( 'group_id' => $cgroup->id ) );
+		$child_group->parent_id = $grandparent_group_id;
+		$child_group->save();
+	}
+}
+add_action( 'bp_groups_delete_group', 'bp_groups_update_orphaned_groups_on_group_delete', 10, 2 );
\ No newline at end of file
diff --git src/bp-groups/bp-groups-functions.php src/bp-groups/bp-groups-functions.php
index cb0753e..7ac4623 100644
--- src/bp-groups/bp-groups-functions.php
+++ src/bp-groups/bp-groups-functions.php
@@ -87,6 +87,7 @@ function groups_get_group( $args = '' ) {
  *     @type string   $slug         The group slug.
  *     @type string   $status       The group's status. Accepts 'public', 'private' or
  *                                  'hidden'. Defaults to 'public'.
+ *     @type int      $parent_id    The ID of the parent group. Default: 0.
  *     @type int      $enable_forum Optional. Whether the group has a forum enabled.
  *                                  If the legacy forums are enabled for this group
  *                                  or if a bbPress forum is enabled for the group,
@@ -105,6 +106,7 @@ function groups_create_group( $args = '' ) {
 		'description'  => '',
 		'slug'         => '',
 		'status'       => 'public',
+		'parent_id'    => 0,
 		'enable_forum' => 0,
 		'date_created' => bp_core_current_time()
 	);
@@ -151,6 +153,7 @@ function groups_create_group( $args = '' ) {
 	$group->description  = $description;
 	$group->slug         = $slug;
 	$group->status       = $status;
+	$group->parent_id    = $parent_id;
 	$group->enable_forum = (int) $enable_forum;
 	$group->date_created = $date_created;
 
@@ -270,7 +273,7 @@ function groups_edit_base_group_details( $group_id, $group_name, $group_desc, $n
  *                                   to the group. 'members', 'mods', or 'admins'.
  * @return bool True on success, false on failure.
  */
-function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status = false ) {
+function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status = false, $parent_id = false ) {
 
 	$group = groups_get_group( array( 'group_id' => $group_id ) );
 	$group->enable_forum = $enable_forum;
@@ -285,6 +288,11 @@ function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_
 	// Now update the status.
 	$group->status = $status;
 
+	// Update the parent ID if necessary.
+	if ( false !== $parent_id ) {
+		$group->parent_id = $parent_id;
+	}
+
 	if ( !$group->save() )
 		return false;
 
@@ -703,6 +711,7 @@ function groups_get_groups( $args = '' ) {
 		'user_id'            => false,          // Pass a user_id to limit to only groups that this user is a member of.
 		'include'            => false,          // Only include these specific groups (group_ids).
 		'exclude'            => false,          // Do not include these specific groups (group_ids).
+		'parent_id'          => false,          // Get groups that are children of the specified group(s).
 		'search_terms'       => false,          // Limit to groups that match these search terms.
 		'group_type'         => '',
 		'group_type__in'     => '',
@@ -722,6 +731,7 @@ function groups_get_groups( $args = '' ) {
 		'user_id'            => $r['user_id'],
 		'include'            => $r['include'],
 		'exclude'            => $r['exclude'],
+		'parent_id'          => $r['parent_id'],
 		'search_terms'       => $r['search_terms'],
 		'group_type'         => $r['group_type'],
 		'group_type__in'     => $r['group_type__in'],
diff --git src/bp-groups/bp-groups-template.php src/bp-groups/bp-groups-template.php
index f08fea5..fa1403e 100644
--- src/bp-groups/bp-groups-template.php
+++ src/bp-groups/bp-groups-template.php
@@ -137,6 +137,8 @@ function bp_groups_directory_permalink() {
  *                                            about groups. Default: true.
  *     @type array|string $exclude            Array or comma-separated list of group IDs. Results will exclude
  *                                            the listed groups. Default: false.
+ *     @type array|string $parent_id          Array or comma-separated list of group IDs. Results will include only
+ *                                            child groups of the listed groups. Default: false.
  *     @type bool         $update_meta_cache  Whether to fetch groupmeta for queried groups. Default: true.
  * }
  * @return bool True if there are groups to display that match the params
@@ -150,6 +152,7 @@ function bp_has_groups( $args = '' ) {
 	$slug         = false;
 	$type         = '';
 	$search_terms = false;
+	$parent_id    = false;
 
 	// When looking your own groups, check for two action variables.
 	if ( bp_is_current_action( 'my-groups' ) ) {
@@ -198,6 +201,7 @@ function bp_has_groups( $args = '' ) {
 		'meta_query'         => false,
 		'include'            => false,
 		'exclude'            => false,
+		'parent_id'          => $parent_id,
 		'populate_extras'    => true,
 		'update_meta_cache'  => true,
 	), 'has_groups' );
@@ -221,6 +225,7 @@ function bp_has_groups( $args = '' ) {
 		'meta_query'         => $r['meta_query'],
 		'include'            => $r['include'],
 		'exclude'            => $r['exclude'],
+		'parent_id'          => $r['parent_id'],
 		'populate_extras'    => (bool) $r['populate_extras'],
 		'update_meta_cache'  => (bool) $r['update_meta_cache'],
 	) );
diff --git src/bp-groups/classes/class-bp-groups-group.php src/bp-groups/classes/class-bp-groups-group.php
index bde4f1e..f16b8c3 100644
--- src/bp-groups/classes/class-bp-groups-group.php
+++ src/bp-groups/classes/class-bp-groups-group.php
@@ -68,6 +68,16 @@ class BP_Groups_Group {
 	public $status;
 
 	/**
+	 * Parent ID.
+	 *
+	 * ID of parent group, if applicable.
+	 *
+	 * @since 2.7.0
+	 * @var int
+	 */
+	public $parent_id;
+
+	/**
 	 * Should (legacy) bbPress forums be enabled for this group?
 	 *
 	 * @since 1.6.0
@@ -214,6 +224,7 @@ class BP_Groups_Group {
 		$this->slug         = $group->slug;
 		$this->description  = stripslashes( $group->description );
 		$this->status       = $group->status;
+		$this->parent_id    = $group->parent_id;
 		$this->enable_forum = $group->enable_forum;
 		$this->date_created = $group->date_created;
 
@@ -282,6 +293,7 @@ class BP_Groups_Group {
 		$this->slug         = apply_filters( 'groups_group_slug_before_save',         $this->slug,         $this->id );
 		$this->description  = apply_filters( 'groups_group_description_before_save',  $this->description,  $this->id );
 		$this->status       = apply_filters( 'groups_group_status_before_save',       $this->status,       $this->id );
+		$this->parent_id    = apply_filters( 'groups_group_parent_id_before_save',    $this->parent_id,    $this->id );
 		$this->enable_forum = apply_filters( 'groups_group_enable_forum_before_save', $this->enable_forum, $this->id );
 		$this->date_created = apply_filters( 'groups_group_date_created_before_save', $this->date_created, $this->id );
 
@@ -324,6 +336,7 @@ class BP_Groups_Group {
 					slug = %s,
 					description = %s,
 					status = %s,
+					parent_id = %d,
 					enable_forum = %d,
 					date_created = %s
 				WHERE
@@ -334,6 +347,7 @@ class BP_Groups_Group {
 					$this->slug,
 					$this->description,
 					$this->status,
+					$this->parent_id,
 					$this->enable_forum,
 					$this->date_created,
 					$this->id
@@ -346,16 +360,18 @@ class BP_Groups_Group {
 					slug,
 					description,
 					status,
+					parent_id,
 					enable_forum,
 					date_created
 				) VALUES (
-					%d, %s, %s, %s, %s, %d, %s
+					%d, %s, %s, %s, %s, %d, %d, %s
 				)",
 					$this->creator_id,
 					$this->name,
 					$this->slug,
 					$this->description,
 					$this->status,
+					$this->parent_id,
 					$this->enable_forum,
 					$this->date_created
 			);
@@ -710,6 +726,8 @@ class BP_Groups_Group {
 	 *                                            See {@link WP_Meta_Query::queries} for description.
 	 *     @type array|string $value              Optional. Array or comma-separated list of group IDs. Results
 	 *                                            will be limited to groups within the list. Default: false.
+	 *     @type array|string $parent_id          Optional. Array or comma-separated list of group IDs. Results
+	 *                                            will be limited to children of the specified groups. Default: false.
 	 *     @type bool         $populate_extras    Whether to fetch additional information
 	 *                                            (such as member count) about groups. Default: true.
 	 *     @type array|string $exclude            Optional. Array or comma-separated list of group IDs.
@@ -761,6 +779,7 @@ class BP_Groups_Group {
 			'group_type__not_in' => '',
 			'meta_query'         => false,
 			'include'            => false,
+			'parent_id'          => false,
 			'populate_extras'    => true,
 			'update_meta_cache'  => true,
 			'exclude'            => false,
@@ -835,6 +854,11 @@ class BP_Groups_Group {
 			$sql['include'] = " AND g.id IN ({$include})";
 		}
 
+		if ( ! empty( $r['parent_id'] ) ) {
+			$parent_id        = implode( ',', wp_parse_id_list( $r['parent_id'] ) );
+			$sql['parent_id'] = " AND g.parent_id IN ({$parent_id})";
+		}
+
 		if ( ! empty( $r['exclude'] ) ) {
 			$exclude        = implode( ',', wp_parse_id_list( $r['exclude'] ) );
 			$sql['exclude'] = " AND g.id NOT IN ({$exclude})";
@@ -948,6 +972,11 @@ class BP_Groups_Group {
 		}
 
 		// Already escaped in the paginated results block.
+		if ( ! empty( $parent_id ) ) {
+			$total_sql['where'][] = "g.parent_id IN ({$parent_id})";
+		}
+
+		// Already escaped in the paginated results block.
 		if ( ! empty( $exclude ) ) {
 			$total_sql['where'][] = "g.id NOT IN ({$exclude})";
 		}
diff --git src/bp-groups/classes/class-bp-groups-template.php src/bp-groups/classes/class-bp-groups-template.php
index 043d8f4..49e5eb6 100644
--- src/bp-groups/classes/class-bp-groups-template.php
+++ src/bp-groups/classes/class-bp-groups-template.php
@@ -165,6 +165,7 @@ class BP_Groups_Template {
 			'slug'               => false,
 			'include'            => false,
 			'exclude'            => false,
+			'parent_id'          => false,
 			'search_terms'       => '',
 			'group_type'         => '',
 			'group_type__in'     => '',
@@ -226,6 +227,7 @@ class BP_Groups_Template {
 				'group_type__not_in' => $group_type__not_in,
 				'include'            => $include,
 				'exclude'            => $exclude,
+				'parent_id'          => $parent_id,
 				'populate_extras'    => $populate_extras,
 				'update_meta_cache'  => $update_meta_cache,
 				'show_hidden'        => $show_hidden,
diff --git tests/phpunit/testcases/groups/class-bp-groups-group.php tests/phpunit/testcases/groups/class-bp-groups-group.php
index d42959c..67948b4 100644
--- tests/phpunit/testcases/groups/class-bp-groups-group.php
+++ tests/phpunit/testcases/groups/class-bp-groups-group.php
@@ -1383,6 +1383,90 @@ class BP_Tests_BP_Groups_Group_TestCases extends BP_UnitTestCase {
 
 		$this->assertEmpty( $groups['groups'] );
 	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_get_by_parent_id() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+		$g3 = $this->factory->group->create( array(
+			'parent_id' => $g2,
+		) );
+		$g4 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'parent_id' => $g1,
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( array( $g2 ), $found );
+	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_get_by_parent_id_ignore_grandparent() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+		$g3 = $this->factory->group->create( array(
+			'parent_id' => $g2,
+		) );
+		$g4 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'parent_id' => $g2,
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( array( $g3 ), $found );
+	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_get_by_parent_id_array() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+		$g3 = $this->factory->group->create( array(
+			'parent_id' => $g2,
+		) );
+		$g4 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'parent_id' => array( $g1, $g2 ),
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEqualSets( array( $g2, $g3 ), $found );
+	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_get_by_parent_id_comma_separated_string() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+		$g3 = $this->factory->group->create( array(
+			'parent_id' => $g2,
+		) );
+		$g4 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'parent_id' => "$g1, $g2",
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEqualSets( array( $g2, $g3 ), $found );
+	}
 }
 
 /**
diff --git tests/phpunit/testcases/groups/functions.php tests/phpunit/testcases/groups/functions.php
index 22f4c53..b97840f 100644
--- tests/phpunit/testcases/groups/functions.php
+++ tests/phpunit/testcases/groups/functions.php
@@ -664,4 +664,37 @@ Bar!';
 		groups_accept_invite( $u2, $g );
 		$this->assertEquals( 0, groups_get_invite_count_for_user( $u2 ) );
 	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_update_orphaned_groups_on_group_delete_top_level() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+
+		groups_delete_group( $g1 );
+
+		$child = groups_get_group( array( 'group_id' => $g2 ) );
+		$this->assertEquals( 0, $child->parent_id );
+	}
+
+	/**
+	 * @group hierarchical_groups
+	 */
+	public function test_update_orphaned_groups_on_group_delete_two_levels() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create( array(
+			'parent_id' => $g1,
+		) );
+		$g3 = $this->factory->group->create( array(
+			'parent_id' => $g2,
+		) );
+
+		groups_delete_group( $g2 );
+
+		$child = groups_get_group( array( 'group_id' => $g3 ) );
+		$this->assertEquals( $g1, $child->parent_id );
+	}
 }
