I generally avoid “marker interfaces” because they don’t allow you to unmark a derived type. But that aside, here are some of the specific cases that I have seen where marker interfaces would be preferable to built-in meta-data support:
- Run-time performance sensitive situations.
- Compatibility with languages that don’t support annotation or attributes.
- Any context where the interested code may not have access to the metadata.
- Support for generic constraints and generic variance (typically of collections).