Not to be pedantic, but the mapping is from ENST to Gene ID, not ENSG.
Anyway, this is due to what UCSC has done with their knownGene table. In the past they had their own transcript IDs, and the knownGene table was based on a set of UCSC genes, and presumably those genes were based primarily on NCBI data.
But now they base the knownGene table on GENCODE genes, and therefore they use Ensembl transcript IDs. The mapping we use to generate the TxDb packages relies on data from the knownToLocusLink table (where LocusLink was what they called Entrez Gene back in the day, and what NCBI has now shortened to just the Gene database). And mapping Ensembl transcripts to NCBI Gene IDs is a non-trivial endeavor, as there are any number of disagreements between those two annotation services as to what is a gene, and where they might be, and what transcripts arise from that gene, and which exons, etc.
So it's not surprising at all that there are things getting lost in translation. IMO there are too many gotchas that arise when trying to map from EBI/EMBL annotations to NCBI and back again, so I always try to stay with whatever annotations I started with.
In your case that would mean you should stick with the EnsDb, and forgo the TxDb, and don't try to get NCBI Gene IDs.