A few alternatives, depending on your needs: google.protobuf.Any is a bit tricky to use, and is fairly expensive on the wire since it serializes the name of the protobuf type as well as its contents:
* If you already know the type of the objects at the receiver side, you can use
map<string, bytes> attributes = 1;
and just store the byte-serialized proto value in the map. This is the "old-fashioned" way to do it, and is still the most wire-efficient and code-simple solution if you know the type ahead of time.
* If you don't, a good alternative to using Any is to roll your own version of it:
message Object {
string protoType = 1;
bytes value = 2;
}
map<string, Object> attributes = 1;
Then on the client side, get the class object from protoType using the PB symbol database (syntax varies by language), and decode value using that.
This may be better than Any, because Any is not just a somewhat recent addition to proto, it has some rather surprising behavior: the proto type you pass to it needs to be the URL where a schema descriptor is being served, and sometimes if you try to pass an Any through various services (like Stackdriver logging, as I found to my dismay) it will not only try to look up that descriptor, but fail the entire RPC if that doesn't work. This is behavior which almost nobody actually needs, and requires you to do a lot of work (exposing an API publicly) to support, so I frankly recommend skipping it unless you have a good reason.
* One thing I don't recommend is something like
message Object { }
map<string, Object> attributes = 1;
and then using proto extensions to extend Object. This was the old (proto2) way to do this, but it got taken out of proto3 because it's a weird maintenance nightmare, the wire formats made the proto code way more complex, and it's prone to Interesting Surprises in several languages, especially Java. Proto extensions aren't quite the work of the Devil, but they're not too far off.