How to identify entities and model relationships
A systematic approach to discovering classes and relationships from requirements, using noun extraction, responsibility testing, and relationship classification.
You just read "Design a library management system" on the whiteboard. You know you need classes. You know they need relationships. But which nouns become classes, which become fields, and which are just noise? Most candidates either freeze here or start typing class Book and hope inspiration strikes.
Entity discovery is the single most important skill in LLD interviews, and it is also the most under-practiced. Get the entities wrong and every pattern you apply later fights against the shape of your model. Get them right and the patterns almost pick themselves. This guide gives you a repeatable, mechanical process you can apply to any prompt in under five minutes.
Why entity discovery matters
Entities are the skeleton of your design. Every class you write, every interface you define, every relationship you draw flows from the entities you chose in the first five minutes. If you pick the wrong entities, you spend the rest of the interview patching a broken model.
I have watched candidates build beautiful Strategy patterns on top of a class model that had Book and Library as a single merged class. The pattern was correct. The entities underneath it were wrong. The interviewer saw it immediately and the conversation went sideways.
Think of entities like the columns in a database schema. Get the columns wrong and no amount of clever queries will save you. Get them right and most queries write themselves.
The good news: entity discovery is not a creative act. It is a mechanical extraction process. You read the requirements, highlight the nouns, filter out the noise, and what remains are your classes. The rest of this guide teaches you exactly that process.
Interview tip: make it visible
Write your entity list on the whiteboard before coding anything. Interviewers score "structured thinking" as a separate dimension. A visible entity list with attributes is evidence of that thinking, even before you write a single line of code.
The noun-extraction technique
This is the core technique. It works for every LLD prompt you will ever see. The process has three steps: extract, filter, promote.
Step 1: Extract all nouns
Read the requirements and underline every noun or noun phrase. Do not judge yet. Do not ask "is this a class?" Just collect.
Here is a sample requirement for a library system:
"The library has multiple branches. Each branch has a collection of books. Members can borrow up to 5 books at a time and must return them within 14 days. A librarian can add or remove books from the catalog. The system tracks fines for overdue books. Each book has a title, author, ISBN, and publication year."
Extracted nouns: library, branches, books, members, librarian, catalog, fines, title, author, ISBN, publication year, days.
That is twelve nouns from one paragraph. Not all of them will become classes. The next step separates signal from noise.
Step 2: Filter the noise
Apply three filters to your noun list:
| Filter | Rule | Examples dropped |
|---|---|---|
| Too vague | System-level or abstract nouns that do not map to a concrete thing | "system", "collection", "time" |
| Primitive attribute | Things that are best represented as a field on another class | "title", "ISBN", "publication year", "days" |
| Duplicate / synonym | Same concept with different names | "catalog" = "collection of books" |
After filtering, our library example shrinks from twelve nouns to a focused set:
| Noun | Verdict | Reasoning |
|---|---|---|
| Library | Entity | Top-level container, has branches |
| Branch | Entity | Distinct location with its own book collection |
| Book | Entity | Core domain object with its own identity and lifecycle |
| Member | Entity | Actor who borrows books |
| Librarian | Entity | Actor who manages the catalog |
| Fine | Entity | Has its own amount, status, calculation rules |
| Catalog | Drop | Synonym for "the set of books in a branch" |
| Title | Attribute | String field on Book |
| Author | Promote? | Could be an entity if books share authors. Explore further. |
| ISBN | Attribute | String field on Book |
| Publication year | Attribute | int field on Book |
| Days | Drop | Constraint (14-day limit), not a thing |
Step 3: Promote hidden entities
Some nouns start as attributes but deserve promotion to full entities. The author example above is a good case. If books share authors and you need to query "all books by this author," then Author should be its own class with a name, biography, and a list of books. If authors are just a display string, keep it as a field.
The verb "borrow" also hides an entity. A borrowing event has a start date, due date, return date, and status. That is too much state for a simple field. It deserves its own class: Loan or BorrowRecord.
For your interview: always look for hidden entities in the verbs. "Reserve," "borrow," "pay," "fine" are all actions that carry state. When an action has a date, a status, or multiple attributes, it is probably an entity.
This three-step process takes under five minutes with practice. Do it on paper before you touch code.
Entity vs. attribute: when something deserves its own class
This is the question that trips up most candidates. Is "Address" a class or a group of fields on Member? Is "Author" its own class or a String? There is a simple heuristic.
Promote to a class when any of these are true:
-
It has its own identity. Can two different instances of this thing exist with different attributes? Two authors can have the same name but different biographies. That is identity. A title string does not have identity.
-
It participates in multiple relationships. If
Authoris referenced byBookand also byEvent(author signing events), it needs to be shared. Shared things need to be entities. -
It has behavior. An
Addressthat just holds street/city/zip is a value object (or even just fields). AnAddressthat can validate itself, format for different locales, or calculate shipping zones has behavior. Behavior means class. -
It changes independently. If the author's biography changes, should every book record update? If yes,
Authoris a shared entity. If no, it is just a copied string.
Here is the decision as a quick flowchart:
I use this decision tree in every LLD interview I coach. If even one question gets a "yes," promote the noun to a class. When in doubt, start with a class. It is easier to inline a class back into a field than to extract one later after you have written 200 lines of code.
The String trap
The most common entity-modeling mistake is representing complex concepts as Strings. String status should be an enum. String address should be a value object. String author might need to be a class. If you find yourself writing String for something with rules or validation, stop and reconsider.
Discovering relationships
Once you have your entities, you need to connect them. Relationships come from verbs and ownership semantics in the requirements.
Read the verbs
Go back to the requirements and underline the verbs this time:
"Members can borrow up to 5 books. A librarian can add or remove books. The system tracks fines."
Each verb implies a relationship:
- "borrow" connects Member to Book (through a Loan)
- "add/remove" connects Librarian to Book
- "tracks" connects the system to Fine (Fine belongs to a Loan)
Classify the relationship type
Use ownership and lifecycle to classify:
| Relationship | Test question | Example |
|---|---|---|
| Association | "Does A know about B, but neither controls the other's lifetime?" | Teacher knows Student |
| Aggregation | "Does A contain B, but B can exist without A?" | Department contains Employees (employees survive if dept is dissolved) |
| Composition | "Does A own B, and B dies when A dies?" | House owns Rooms (rooms disappear if house is demolished) |
| Inheritance | "Is B a specialized version of A?" | EBook is a Book |
For the library system, the relationships fall out naturally:
- Library composes Branches (destroy the library, branches go too)
- Branch aggregates Books (a book can be transferred between branches)
- Member associates with Book through Loan (neither owns the other)
- Loan composes Fine (no loan, no fine)
- Librarian is-a specialized Member (or a separate actor, depending on your requirements)
Map the multiplicity
Every relationship needs a count on both sides. Ask: "How many Bs can one A have? How many As can one B belong to?"
| Relationship | Multiplicity | Reasoning |
|---|---|---|
| Library to Branch | 1 to many | One library, multiple branches |
| Branch to Book | 1 to many | One branch holds many books |
| Member to Loan | 1 to many | One member, up to 5 active loans |
| Loan to Book | 1 to 1 | Each loan is for exactly one book |
| Loan to Fine | 1 to 0..1 | A loan may or may not generate a fine |
Put all of this into a class diagram and you have your entity model:
That diagram took under five minutes to derive and it tells the interviewer everything: you know the domain, you understand relationships, and you can reason about ownership.
Worked example: "Design a Library Management System"
Let me walk through the full process end to end, exactly as you would do it on a whiteboard.
Requirements (given by interviewer)
"Build a library management system. The library has branches in different locations. Each branch maintains a catalog of books. Members register with the library and can borrow books from any branch. There is a limit of 5 books per member. Books must be returned within 14 days or a fine is charged. Librarians manage the inventory. Members can also reserve books that are currently checked out."
Round 1: Noun extraction
I read through and highlight every noun:
library, branches, locations, catalog, books, members, library (dup), books (dup), branch (dup), limit, books (dup), member (dup), days, fine, librarians, inventory, members (dup), books (dup), reservation.
Deduplicated noun list: library, branch, location, catalog, book, member, limit, days, fine, librarian, inventory, reservation.
Round 2: Filter and classify
| Noun | Verdict | Reasoning |
|---|---|---|
| Library | Entity | Top-level aggregate |
| Branch | Entity | Has its own location, catalog, and identity |
| Location | Attribute | String/value on Branch |
| Catalog | Drop | Just "the books in a branch" |
| Book | Entity | Core domain object |
| Member | Entity | Actor with registration, borrowing rules |
| Limit | Drop | Business rule (constant = 5), not a thing |
| Days | Drop | Business rule (constant = 14) |
| Fine | Entity | Has amount, status, calculation logic |
| Librarian | Entity | Different permissions than Member |
| Inventory | Drop | Synonym for "books in a branch" |
| Reservation | Entity | Hidden in verb "reserve." Has status, dates, expiry logic. |
Round 3: Discover hidden entities from verbs
| Verb | Hidden entity | Why |
|---|---|---|
| borrow | Loan | Tracks borrow date, due date, return date, status |
| reserve | Reservation | Tracks reserved date, expiry, notification status |
| register | No | Registration is a one-time action, Member covers it |
| charge (a fine) | Fine (already found) |
Final entity list
Seven core entities: Library, Branch, Book, Member, Librarian, Loan, Reservation, Fine.
That is the right number. I have seen candidates stop at three (Book, Member, Library) and candidates go to fifteen. Seven to nine is the sweet spot for a 45-minute library problem.
Assigning attributes
For each entity, list 3-5 attributes. No more. You can always add fields later.
public class Book {
private String isbn;
private String title;
private Author author;
private int publicationYear;
private BookStatus status; // AVAILABLE, CHECKED_OUT, RESERVED, LOST
}
public class Member {
private String memberId;
private String name;
private String email;
private List<Loan> activeLoans;
private List<Reservation> reservations;
}
public class Loan {
private Member member;
private Book book;
private LocalDate borrowDate;
private LocalDate dueDate;
private LocalDate returnDate;
private LoanStatus status; // ACTIVE, RETURNED, OVERDUE
}
public class Reservation {
private Member member;
private Book book;
private LocalDate reservedDate;
private LocalDate expiryDate;
private ReservationStatus status; // PENDING, FULFILLED, EXPIRED, CANCELLED
}
Notice the pattern: every entity has an identity field, a status enum, and 2-4 domain-relevant fields. This is a reliable template.
Interview tip: use enums for status
Whenever you see an entity that can be in different states (a loan that is active, returned, or overdue), model that as an enum. It shows the interviewer you think about state management, and it opens the door for the State pattern discussion later.
The responsibility test
You have your entities and their attributes. Now stress-test the model. The responsibility test asks one question for every pair of entities:
"Do these two things change for different reasons?"
If yes, they should be separate classes. If they always change together and for the same reason, maybe they should merge.
This comes from the Single Responsibility Principle, but applied at the entity level rather than the method level.
Applying the test
| Pair | Change together? | Verdict |
|---|---|---|
| Book and Author | No. Author's biography changes independently of book data. | Separate classes. |
| Loan and Fine | Partially. A fine only exists because of a loan, but fine calculation rules change independently (e.g., new fine policy). | Separate classes, composed. |
| Member and Librarian | They share identity fields but have different permissions and operations. | Separate classes (or Librarian extends Member). |
| Branch and Library | A branch's catalog changes independently of other branches. Library just groups them. | Separate classes, composed. |
| Loan and Reservation | Different lifecycles. A reservation becomes a loan but they track different data. | Separate classes. |
If you find two entities that always change together and share the same lifecycle, merge them. For instance, if Address only ever appears as part of Branch and never independently, it might just be fields on Branch rather than its own class.
The inverse mistake is equally common: keeping things merged that should be separate. If you have a Book class with borrowerName, borrowDate, and dueDate fields directly on it, you have merged Book with Loan. Split them. A book can exist without being borrowed.
Common entity mistakes
These are the patterns I see go wrong most often in interviews.
1. Splitting too early
Creating HardcoverBook, PaperbackBook, AudioBook as separate classes before you know whether the system treats them differently. Premature inheritance creates rigid hierarchies. Start with a single Book class and a BookFormat enum. Only split into subclasses when the behavior genuinely differs (e.g., AudioBook has a duration field and a streaming method that others do not).
The rule of thumb: if the only difference is data (fields), use composition or an enum. If the difference is behavior (methods), consider inheritance.
2. Merging too much
The opposite problem. Stuffing everything into three mega-classes: Library, Book, User. A class with 20 fields and 15 methods is a sign you missed entities. If your User class has borrowBook(), returnBook(), payFine(), reserveBook(), addBook(), removeBook(), you have merged Member and Librarian concerns.
Break it up. Each class should have one clear reason to exist.
3. Naming things wrong
Names matter more than candidates think. Common naming mistakes:
| Bad name | Problem | Better name |
|---|---|---|
Data | Meaningless | Name it by what data: BookRecord, LoanDetails |
Manager | Vague, becomes a god class | LoanService, CatalogManager with a focused scope |
Info | Same as Data | MemberProfile, BookMetadata |
Helper / Util | Dumping ground | Move methods to the entity they operate on |
Object suffix | Redundant (everything is an object) | Drop it: Book not BookObject |
Your class names are your first communication to the interviewer. BorrowRecord tells them you understand the domain. DataObject1 tells them you do not.
4. Forgetting enums
When you see a concept with a fixed set of values (book status, loan state, member type), model it as an enum. Not as a String, not as an int, not as a boolean. Enums are self-documenting and type-safe.
public enum BookStatus {
AVAILABLE,
CHECKED_OUT,
RESERVED,
LOST,
UNDER_MAINTENANCE
}
This is a tiny thing that sends a strong signal. Interviewers notice it.
5. Ignoring the "through" entity
"Members borrow books" does not mean Member has a direct reference to Book. The borrowing action itself (the Loan) is an entity. Every time two entities interact through a time-bound, stateful process, there is a "through" entity hiding in the verb.
Other examples: Enrollment between Student and Course. Payment between Customer and Order. Appointment between Doctor and Patient. Miss these and your model becomes a tangled web of direct many-to-many references.
Test Your Understanding
Quick recap
-
Entity discovery is a mechanical process, not a creative one. Extract nouns, filter noise, promote hidden entities from verbs.
-
Use the noun-extraction technique: read requirements, highlight nouns, apply three filters (too vague, primitive attribute, duplicate).
-
Promote a noun to a class when it has its own identity, participates in multiple relationships, has behavior, or changes independently.
-
Discover relationships by reading verbs and classifying ownership: association (knows about), aggregation (contains but does not own), composition (owns, dies together).
-
Apply the responsibility test to every entity pair: "Do these change for different reasons?" If yes, keep them separate.
-
Watch for through entities hiding in verbs. "Borrow," "reserve," "enroll," and "pay" almost always produce their own class.
-
Name your classes after domain concepts (Book, Loan, Reservation), not technical roles (Manager, Helper, Data).
Related concepts
- OOD interview approach covers the full 5-step framework for LLD interviews, including how entity discovery fits into the bigger picture.
- Association explains the baseline relationship type where objects know about each other without ownership.
- Aggregation covers the "contains but does not own" relationship, with lifecycle semantics.
- Composition is the strongest relationship: the container owns and controls the contained object's lifetime.