Como relacionar ArrayList

Seguinte, estou tentando fazer uma aplicação bancaria e tenho uma superclasse Pessoa que é pai das classe ClientePJ, ClientePF e em cada uma das classe filhas tem um atributo do tipo Endereco. Tenho um arrayList nas classes ClientePJ, ClientePF com nome, cpf, id e na classe Endereço guardo as informações do cep, logradouro, rua entre outras coisas relacionadas a endereço.

Eu gostaria de quando o usuário quisesse criar uma conta, ele digitaria o cpf ou o cnpj e as informações do cliente e seu respectivo endereço aparecesse na tela.
Com o atributo do tipo Endereço nas classes filhas consegui exibir as informações dos clientes e o endereço, o problema é que quando eu adiciono vários clientes tanto PJ como PF o endereço não corresponde a pessoa certa, pq eu adiciono um cliente e passo as informações dele para o construtor e dentro desse construtor eu adiciono o endereco na lista de endereço, o problema ocorre ai, pq eu adiciono o cliente na listaPF no id 1 e o endereco no mesmo id e quando eu crio um clientePJ ele recebe o id 1 já que são listas de clientes são distintas o enderco como é o mesmo tanto para cliente PJ e PF ele recebe id 2 e quando vou buscar os clientes com o id tal o endereço vem errado.

Não faço a minima ideia de como resolver isso.

Nessa classe Endereco tenho os métodos get e set, mas retirei pra postar aqui.
public class Endereco {

public static ArrayList<Endereco> listaEnder = new ArrayList<Endereco>();

protected static int gerarId=0;//Do endereço
protected String id;
private String tipe="Residencial";
private String tipoDeLogradouro;
private String logradouro;
private int numero;
private String bairro;
private String cidade;
private String estado;
private String cep;
PessoaJuridica pessoa = new PessoaJuridica(cep);

public Endereco(String tipe, String tipoDeLogradouro, String logradouro, int numero, String bairro, String cidade, String estado, String cep) {
    this.tipe = tipe;
    this.tipoDeLogradouro = tipoDeLogradouro;
    this.logradouro = logradouro;
    this.numero = numero;
    this.bairro = bairro;
    this.cidade = cidade;
    this.estado = estado;
    this.cep = cep;
    id = gerarID();
    
}

public Endereco(String tipoDeLogradouro, String logradouro, int numero, String bairro, String cidade, String estado, String cep) {
    this.tipoDeLogradouro = tipoDeLogradouro;
    this.logradouro = logradouro;
    this.numero = numero;
    this.bairro = bairro;
    this.cidade = cidade;
    this.estado = estado;
    //if(listaCEP(cep)){
        
    //}else{
        //listaEnder.add(Endereco);
        this.cep = cep;
        id = gerarID();
    //}  
}

protected String gerarID(){
    this.gerarId++; 
    return "Endereço: "+gerarId;
}

@Override
public String toString() {
    return "\nEndereco\n" + "ID: " + id + "\nTipo da Residência: " + tipe + "\nTipo Do Logradouro: " + tipoDeLogradouro + "\nLogradouro: " + logradouro + "\nNumero: " + numero + "\nBairro: " + bairro + "\nCidade: " + cidade + "\nEstado: " + estado + "\nCEP: " + cep + "\n";
}  

}
identar texto pre-formatado em 4 espaços

abstract public class Pessoa {
static protected int gerarId=0;
protected String id;
protected String nome;
Endereco endereco;
abstract protected String gerarID();

public String getNome() {
    return nome;
}

public String getId() {
    return id;
}

public void setEndereco(Endereco endereco) {
    this.endereco = endereco;
}

@Override
public String toString() {
    return "Pessoa{" + '}';
}

}

public class PessoaFisica extends Pessoa{
private String cpf;
private static int geraId=0;
public static ArrayList<PessoaFisica> listaPF = new ArrayList<PessoaFisica>();

public PessoaFisica(String nome, Endereco endereco, String cpf){
    if(validaCPF(cpf)){
        this.cpf = cpf;
        this.nome = nome;
        setEndereco(endereco);
        id = gerarID();
        Endereco.listaEnder.add(endereco);
    } 
}public PessoaFisica(String nome, Endereco endereco, String cpf){
    if(validaCPF(cpf)){
        this.cpf = cpf;
        this.nome = nome;
        setEndereco(endereco);
        id = gerarID();
        Endereco.listaEnder.add(endereco);
    } 
}

public PessoaFisica(String cpf){//só pra pesquisar
    if(validaCPF(cpf)){
        this.cpf=cpf;
    }
}
@Override
protected String gerarID(){
    this.gerarId++; 
    return "Pessoa Fisica - "+gerarId;
}

private boolean validaCPF(String CPF){        
    return cpf; 
}

@Override
public String toString(){//Se colocar o endereço para imprimir aqui da erro, pois o Endereco na classe Pessoa está privado************
    return "PessoaFisica\n" + "ID: " +id+"\nNome: "+nome+"\nCPF: "+cpf+endereco+"\n";
}

public int buscarCPF(String cpf){
    int posicao=-1;
    
    for(int i=0;i<lista.size();i++){
        if(lista.get(i).getCPF().equals(cpf)){
            posicao=i;
        } 
    }     
    return posicao;
}

}

A classe PJ está parecida com a PF, porém tem o ArrayList List PJ

public static ArrayList listaPJ = new ArrayList();

Como estão essas classes?
Entendo que deveria ser algo assim

public class Endereco {
    //coisas do endereco
}

E

public class Pessoa {
    private Endereco endereco;
   //outras coisas de pessoa
}