Share root slug for Child Page and Custom Post Type (prioritizing child pages over posts)

I want to have some specific child pages for the page “Whatever”, and I want them to be available at site.url/whatever/child-page-name

What I want to do is to prioritize pages during the loading process, so that if a child page of “Whatever” exists with the requested name, it should always be loaded (even if a CPT exists with said name).

If the child pages have to be Pages (posts of the page type), then you can use the parse_request hook to conditionally change the request type, which in your case is from a custom post type request to a standard (child) Page request, which means that is_page() would return true and WordPress would also load the correct template for Pages like page-whatever.php.

Working example, tried & tested on WordPress 5.8.1:

Note: get_page_uri() is used to retrieve the “directory” path of the child Page, so if parent is the parent Page slug and child is the child Page slug, then the path would be parent/child.

add_action( 'parse_request', 'my_parse_request' );
function my_parse_request( $wp ) {
    $post_type="whatever"; // set the post type slug
    // and the "whatever" below is the Page slug

    // This code checks if the path of the current request/page URL begins with
    // "whatever/" as in https://example.com/whatever/child-page-name and also
    // https://example.com/whatever/child-page-name/page/2 (paginated request).
    // We also check if the post_type var is the post type set above.
    if ( preg_match( '#^whatever/#', $wp->request ) &&
        isset( $wp->query_vars['post_type'], $wp->query_vars['name'] ) &&
        $post_type === $wp->query_vars['post_type']
    ) {
        $posts = get_posts( array(
            'post_type' => 'page',
            'name'      => $wp->query_vars['name'],
        ) );

        // If a (child) Page with the same name/slug exists, we load the Page,
        // regardless the post type post exists or not.
        if ( ! empty( $posts ) ) {
            $wp->query_vars['pagename'] = get_page_uri( $posts[0] );

            unset( $wp->query_vars['post_type'], $wp->query_vars['name'],
                $wp->query_vars[ $post_type ] );
        }
    }
}