Mastering JPA with PostgreSQL: How to Tame Uppercase Tables and Columns

Introduction

When using PostgreSQL with JPA, uppercase identifiers can become a source of subtle bugs. PostgreSQL lowercases unquoted identifiers, so entity mappings must be explicit when your schema uses uppercase table or column names.

1. Use Explicit @Table and @Column Names

Map fields to exact identifiers in your schema:

@Entity
@Table(name = "\"MY_TABLE\"")
public class MyEntity {
  @Id
  @Column(name = "\"ID\"")
  private Long id;

  @Column(name = "\"FIRST_NAME\"")
  private String firstName;

  @Column(name = "\"LAST_NAME\"")
  private String lastName;
}

The explicit quoting preserves case sensitivity in PostgreSQL.

2. Configure Hibernate Physical Naming Strategy

If naming strategy transforms identifiers, mappings may still break. Use PhysicalNamingStrategyStandardImpl to preserve names exactly as declared in annotations.

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

3. Match Migrations to the Same Naming Rules

Your migration scripts must also define quoted uppercase names:

CREATE TABLE "MY_TABLE" (
  "ID" SERIAL PRIMARY KEY,
  "FIRST_NAME" VARCHAR(50),
  "LAST_NAME" VARCHAR(50),
  "CREATED_AT" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

If entities and migrations do not use the same conventions, runtime mapping errors are very likely.

Common Pitfall

A frequent mistake is quoting names in entities but not in migration scripts, or vice versa. Keep both layers aligned from day one.

Conclusion

To make JPA work reliably with uppercase PostgreSQL identifiers:

  • Use explicit quoted names in @Table and @Column.
  • Disable automatic case transformations with a compatible physical naming strategy.
  • Keep Flyway or Liquibase migrations consistent with the same naming approach.

This prevents hard-to-debug mapping issues and keeps your persistence layer predictable.