Code-first O/R mapping is actually rather silly.
Code-first. It's a way of defining mappings for O/R mappers by hand-writing entity classes and then hand-writing mapping files (either by using shortcuts like conventions or by a fluent api which allows you to setup the mappings rather quickly) to a database which might not exist yet. I find using that kind of system rather odd. The thing is that O/R mapping is about an abstract entity definition which is realized in both a class definition and a table/view definition, in such a way that there is a mapping definable between the two definitions (class and table) so instances of the abstract entity definition (the data!) can flow between instances of the two definitions: from a table row to an entity class instance and back or vice versa. The work needed to perform that flow of entity instances is done by an O/R mapper.
Starting with code in the form of entity classes is equally odd as starting with a table: they both require reverse engineering to the abstract entity definition to create the element 'on the other side': reverse engineer the class to the abstract entity definition to create a table and the mappings is equal to reverse engineering a table to a class and create the mappings. What's the core issue is that if you start with a class or a table, you start with the end result of a projection of an abstract entity definition: the class didn't fall out of the sky, it was created after one determined the domain had such a type: e.g. 'Customer', with a given set of fields: Id, CompanyName, an address etc.
What if that abstract entity definition which was used to create the class or table was in a model which contained all of the domain types for the domain used in the software to build? That would avoid a reverse engineering step to get 'the other side' (class if you start from a table, table if you start from a class), and at the same time it would give a couple of benefits: you can create overviews of the model and more importantly, changes in the domain can be applied directly into the model which then ripple through to classes and tables in the right form, without you needing to worry how that should be done correctly, and without reverse engineering steps which might ignore information which was present in the actual model.
I know the whole idea of 'code first' comes from the fact developers want to write code and think in code and want to persist objects to the database, but that's not what happens: you don't persist objects to a database, you persist their contents, which are the entity instances. It might very well be that an entity class instance (so an object) contains more data than the entity instance, so storing 'the object' then doesn't cover it. Serializing an object is a good metaphor here: with serialization, the object isn't serialized, but a subset of its data, to a form which might not match its source. When deserializing the data into e.g. javascript objects are we then still talking about the original .NET object? No of course not, it's about the data inside the object which lives on elsewhere.
Isn't it then rather odd that when serializing 'objects' to JSON, the overall consensus is that the data is serialized, but when the same object is serialized to a table row, it's actually persisted as a whole? If you are still convinced O/R mapping is about persisting objects, what happens with 'your object', persisted to a table row, if that object is read by a different application, which targets the same database, and which doesn't use an O/R mapper? That application, written in an entirely different language even, can perfectly fine read and consume the entity instance stored in the table row, without even knowing you considered it a persisted .NET object. Because, surprise, the contents of the table row isn't a persisted object, it's a persisted entity instance, an instance of an abstract entity definition, not an instance of a class definition.
But let's say you simply want to work with code only, you don't want to look at models other than when they wear swim gear. Code, being text, has some side effects which might not make it the best medium to define domain models in. Code is readable and changeable easily but to get an overview what's going on, a text editor isn't sufficient anymore, tooling is needed to get proper overview how the model looks like, what the associations are, which inheritance relationships are present. One can't do that by simply looking at the code, the code has to be interpreted or better: reverse engineered to a model, to be able provide the information you're looking for. With a small, 10 entity large model in the form of classes this might work, but if you have to work with a more real-life model with 50 or 100 or even more entities, it's not going to be easy at all.
In case you have a hard time grasping how little one can determine from code alone, try to determine how a database looks like when all you have is 50 tables in DDL SQL statements, complete with their unique constraints and foreign key constraints. It's not a surprise to many that years ago database developers already realized that without proper tooling working with larger relational schemas would be a big nightmare. Strange that code-first using developers don't have that problem at all. At least they don't admit it, otherwise they wouldn't be using code-first at all.
Though let's ignore that for a second. Let's say you as a code-first-I-persist-objects kind of developer have the overview of the model in your code by simply looking at a couple of classes. Are you then problem free? Not really. You see, code-first hides the other side of the picture, or better: a construct in code-first might have devastating results for the other side. E.g. some people have the urge to create a common base class / entity for all their entities in which they define fields like 'ModifiedBy', 'CreatedOn' etc. so all entities will have these fields, and they only have to define them once.
However, there's a problem: inheritance in memory with objects is cheap, it's expensive in a relational database, as with every query, joins will be added for all super/subtypes, if the inheritance is in the form of Target per entity. Is this visible in the code? Is this visible elsewhere? Likely not. Code-first systems often provide a way to use shortcuts: to define repetitive constructs once through conventions. This might hide the results done to the relational schema, as it's unclear how the tables might look like and how they'll result in queries at runtime, simply because the way code is constructed for in-memory use is used as the preferred structure for the relational model as well. Starting from tables of course also hides the other side from the picture, however choices in the DB don't have these kind of effects in code, most of the time.
A better choice is to define the abstract entity model first, use model first with this model to produce both sides, so changes determined in the domain will be reflected as changes in the abstract model and through that as changes to the classes and tables. As it's a model, it can be used as such, so it's easier to make changes, to get overviews from various perspectives and to make sure the changes made to the model are reflected correctly in the classes and tables. It's almost 2014, doing arcane work like in the early days of relational databases and DDL SQL scripts is not necessary anymore. Unless you fancy typing everything out, like a human code generator, you know the people who are replaceable with a tool.