When treated as a String, the first three characters of ParentId represent the object prefix, which can be used to search for the object in the getGlobalDescribe map.
for example.
// This will be set to the object description metadata if found
Schema.DescribeSObjectResult object_desc = null;
// Get the Id we're searching for
String parent_id = feed_item.ParentId;
// Search every object in the getGlobalDescribe() map to check key prefixes
for( Schema.SObjectType t : Schema.getGlobalDescribe().values() ){
Schema.DescribeSObjectResult desc = t.getDescribe();
// If the Id starts with this objects prefix, then we know the type
if( parent_id.startsWith( desc.getKeyPrefix() )){
object_desc = desc;
return;
}
}
if( object_desc != null ){
System.debug('Object type is: ' + object_desc.getName() );
SObject record = Database.query( 'SELECT Name FROM ' + object_desc.getLocalName() + ' WHERE Id = :parent_id" );
System.debug('Object name is: ' + record.get('Name'));
}
If you wanted to return a different field for each object, you'd have to check the object type before building the query, include the relevant field, and then return that.
i.e.
if( object_desc.getLocalName() == 'Contact' ){
String name = [SELECT LastName FROM Contact WHERE Id = :parent_id].LastName;
}