Imagine you want to capture the "Industry" of your leads/accounts as this information might be valuable for reporting and BI. Every organization has different definitions of "industries" because there is no global standard list of industries that is useful for everyone. So you decide to create and maintain your own list of industries. Now the problem becomes: Should you implement this list as an "Industry" entity or should you simply create an OptionSet with the list of industries?
As everything in the technology consulting industry (pun intended), the answer is always: It depends! There is no exact formula of science to solve this dilemma but I've had numerous discussions with colleagues and customers in this respect and I thought of gathering some guidance that might help you decide:
1. How often does this list change and who maintains it?If your list of industries is changing often or if you expect business users to contribute by maintaining this list, it is recommended you implement as a custom entity rather than option set. The reason is that the custom entity adds richer flexibility to create, update or remove values without having to involve IT. You can easily control who can edit the list by leveraging the security roles on the custom entity. However, if your list rarely changes (e.g. list of countries) and it needs to go through IT then you should probably use Option Set.
2. Do you need to support multiple languages?For us in Canada we usually always implement CRM in both English and French. If your industry list is defined as an OptionSet you can support languages much easier because it is just a matter of translating labels so that each user will always see the list in their preferred language. However, if you use a custom entity, the list is data (instead of metadata) and data does not have the notion of language. Things get complicated here. The typical solution is to use a concatenated primary fields in which a workflow automatically appends English and French labels together with a separator. For example you have an industry record called "Travel / Voyage". But this gets too complex if you have more than 2 languages and creates unnecessary long labels. Not to mention language laws dictating which language should appear first can cause a headache. For this aspect, the winner is by far Option Sets.
3. Do you need to capture additional fields?Imagine in our example, you also need to capture an industry code and size along with the industry name. It would be almost impossible to achieve this with Option Sets so you would definitely need to implement your industry list as a custom entity. Even if today you only need the name, consider whether it is likely that in the future you have to capture additional attributes and if so, you should favor using a custom entity over Option Sets.
4. Environment transport and synchronizationThe nice thing about option sets is that when you transport a solution you are also transporting all the labels and values to your target environment and you are sure that the list is consistent in your dev/test/prod environments so you can rely on specific values existing in the list. However, if you implement as an entity, you will never know who will create, update or delete values from one environment and not the other. So you will end up with different value in each environment. Furthermore, you might end up with equal values but different Ids. For example, you might have industry "automobile" in dev with a specific GUID but the same industry in production with a different GUID. This takes me to the next point about:
5. Workflows and reports/viewsYou might want to do industry specific reports or workflows and include logic such as "if this customer is in the banking industry then do X". Using OptionSets this is safe because the value "Banking Industry" is consistent across all environments so you can add such condition to your workflow. However, if you use a custom entity, you cannot rely on values having the same GUID in all environments so you cannot define such logic safely. The workaround would be that in your workflow/view/report you say "if industry.name contains 'banking' then do X". This works in most cases but is not completely safe; for example, somebody might have renamed "banking" to "finance" and suddenly your workflow is broken. The safest is to use an OptionSet which you are sure will exist for a specific value. If you rely on reports and workflows such as the one described above you might be better off using Option Sets.
6. Dependent listsConsider whether your list will have another dependent list. For example list of states/provinces depends on the value selected from the list of countries. You can achieve dependent lists as both OptionSets and custom entities. The only difference is that for custom entities it is easier because you don't need to write any code, simply configure the form to show only states/provinces related to the country selected (assuming there is a relationship between state/province and country). I think this is the least important factor but is a small advantage of custom entities as it is easier to filter the list based on another related value. If you define your list as a custom entity you can even do advanced filtering such as displaying only industries which exist in the country of the current lead (assuming N:N relationship between country and industry). That can be much harder to do via OptionSet (custom development) while it is just a matter of configuring the form in the case of custom entity.
I usually go in the order above to make a decision as the first items have more impact than the last items of the list above. I hope this can help you assess the best solution for your situation, let me know if you have other considerations I missed!