Most 3D engines do neither of these things.
Euler angle rotations are very messy to try to compose. If you have one object rotated on all three axes, and you want to rotate it about an arbitrary world axis, the trig gets... yikes. And the result has discontinuities (you have to wrap around from 180 to -180 somewhere) which makes comparing or interpolating rotations more difficult.
Basis vectors are much better behaved, but redundant. If you store all three basis vectors, that's a whole rotation matrix, 9 floats to lug around and update anytime something changes, for something that only really has three degrees of freedom. Multiplying two rotations in this form means 27 multiplication and 18 addition operations. Matrices/basis vectors interpolate a bit better than Euler angles, without discontinuities or gimbal artifacts, but need re-orthonormaliztion to keep them from squashing in transit, and they can't interpolate 180 degrees without special handling.
So the usual internal memory representation for a rotation is a quaternion. A quaternion is 4 floats (a tiny bit heavier than Euler angles, but still lighter weight than 2 basis vectors and less than half the size of a matrix), representing a point on a unit hypersphere with three imaginary coordinates.
You can form a quaternion from an angle and a unit vector axis to rotate around like so:
q.w = cos(angle/2f);
q.x = sin(angle/2f) * axis.x;
q.y = sin(angle/2f) * axis.y;
q.z = sin(angle/2f) * axis.z;
Composing two rotation quaternions costs 16 multiplies and 12 adds, substantially cheaper than with matrices/basis vectors (and skipping the trig hell of Euler angles), and they interpolate flawlessly over 180 degrees, much more cheaply than the alternatives.
There are downsides: ransforming a vector by a quaternion is slower than with a matrix/basis vectors. So we'll still convert these to a matrix when we expect to do a lot of that.
A transform will usually keep a cached local-to-world matrix (or its inverse), updated lazily when trying to do any vector operations if the source of truth (translation vector, scale triplet, rotation quaternion, and parent transform) has changed in the meantime. We use this cached matrix to furnish fast vector transformations, or upload to the GPU to transform all the vertices in a mesh. But we don't manipulate it as our way to store the object's rotation, and it can be omitted from serialized data since we can rebuild it from the quaternion & co whenever we need.
Now, quaternions aren't the most intuitive to read and manipulate by hand, so engines typically convert them to Euler angles wherever a rotation is displayed to a human user, like in an inspector panel or text format file, or by exposing Euler angle options in the API. But it's still a quaternion under the hood.