Although you do need Content Items that use your reusable content, it IS possible (with a bit of a 'hack') to get just your Reusable content data without needing to know the inheriting class.
Reusable Schemas are part of the ContentItemCommonData which is retrieved when you do the normal ContentItemQueryBuilder().ForContentTypes. However, in code they are an Interface with no object. The IWebPageQueryResultMapper and IContentItemQueryResultMapper can map your page to a given Content Type, but the trouble of course is if you are grabbing MANY Content types, you won't know which to map to.
The solution? Make a Fake Content Type class that inherits your interface, register it and map to that type! The mapper doesn't know it's mapping the 'wrong' content type, and since you're only mapping the Reusable Schema, it won't care because that data is returned regardless if it's one class or another, it's in the Common Data.
Here's some code samples:
The Reusable Schema
public interface IBaseMetadata
{
/// <summary>
/// Code name of the reusable field schema.
/// </summary>
public const string REUSABLE_FIELD_SCHEMA_NAME = "Base.Metadata";
/// <summary>
/// MetaData_PageName.
/// </summary>
public string MetaData_PageName { get; set; }
/// <summary>
/// MetaData_Title.
/// </summary>
public string MetaData_Title { get; set; }
/// <summary>
/// MetaData_Description.
/// </summary>
public string MetaData_Description { get; set; }
/// <summary>
/// MetaData_Keywords.
/// </summary>
public string MetaData_Keywords { get; set; }
/// <summary>
/// MetaData_NoIndex.
/// </summary>
public bool MetaData_NoIndex { get; set; }
/// <summary>
/// MetaData_OGImage.
/// </summary>
public IEnumerable<IGenericHasImage> MetaData_OGImage { get; set; }
}
My "Fake" Class for mapping:
/// <summary>
/// This page type doesn't actually exist, and is only for mapping
/// </summary>
[RegisterContentTypeMapping(CONTENT_TYPE_NAME)]
public partial class BaseMetadataForMapping : IWebPageFieldsSource, IBaseMetadata
{
/// <summary>
/// Code name of the content type.
/// </summary>
public const string CONTENT_TYPE_NAME = "Base.Metadata.ForMapping";
/// <summary>
/// Represents system properties for a web page item.
/// </summary>
[SystemField]
public WebPageFields SystemFields { get; set; }
/// <summary>
/// MetaData_PageName.
/// </summary>
public string MetaData_PageName { get; set; }
/// <summary>
/// MetaData_Title.
/// </summary>
public string MetaData_Title { get; set; }
/// <summary>
/// MetaData_Description.
/// </summary>
public string MetaData_Description { get; set; }
/// <summary>
/// MetaData_Keywords.
/// </summary>
public string MetaData_Keywords { get; set; }
/// <summary>
/// MetaData_NoIndex.
/// </summary>
public bool MetaData_NoIndex { get; set; }
/// <summary>
/// MetaData_OGImage.
/// </summary>
public IEnumerable<IGenericHasImage> MetaData_OGImage { get; set; }
}
And here's where I take the WebPageContentQueryDataContainer / ContentQueryDataContainer (that's actually of type Generic.Home) and map it:
// Even though the result has a content type of Generic.Home, this works!
var mappedResult = _webPageQueryResultMapper.Map<BaseMetadataForMapping>(result);
if(mappedResult is IBaseMetadata metadata) {
// You now have your metadata mapped!
}